1616package net .sf .fdshare ;
1717
1818import android .annotation .TargetApi ;
19- import android .content .ContentResolver ;
2019import android .content .Context ;
2120import android .net .LocalServerSocket ;
2221import android .net .LocalSocket ;
2322import android .os .*;
24- import android .support .annotation .BinderThread ;
2523import android .support .annotation .IntDef ;
2624import android .support .annotation .NonNull ;
2725import android .support .annotation .VisibleForTesting ;
28- import android .support .annotation .WorkerThread ;
2926import android .util .Log ;
3027
3128import java .io .Closeable ;
3229import java .io .File ;
3330import java .io .FileDescriptor ;
3431import java .io .FileInputStream ;
35- import java .io .FileNotFoundException ;
3632import java .io .FileOutputStream ;
3733import java .io .IOException ;
34+ import java .io .InputStream ;
35+ import java .io .OutputStream ;
3836import java .io .OutputStreamWriter ;
3937import java .io .RandomAccessFile ;
4038import java .io .Writer ;
4139import java .lang .Process ;
4240import java .lang .annotation .Documented ;
4341import java .lang .annotation .Retention ;
4442import java .lang .annotation .RetentionPolicy ;
45- import java .lang .ref .PhantomReference ;
4643import java .lang .reflect .Field ;
4744import java .nio .ByteBuffer ;
4845import java .nio .ByteOrder ;
4946import java .nio .channels .Channels ;
50- import java .nio .channels .FileChannel ;
51- import java .nio .channels .Pipe ;
5247import java .nio .channels .ReadableByteChannel ;
5348import java .util .UUID ;
49+ import java .util .concurrent .ArrayBlockingQueue ;
50+ import java .util .concurrent .BlockingQueue ;
5451import java .util .concurrent .SynchronousQueue ;
5552import java .util .concurrent .TimeUnit ;
5653import java .util .concurrent .atomic .AtomicBoolean ;
54+ import java .util .concurrent .locks .Condition ;
5755import java .util .regex .Matcher ;
5856import java .util .regex .Pattern ;
5957
@@ -196,38 +194,43 @@ public static FileDescriptorFactory create(Context context) throws IOException {
196194
197195 @ VisibleForTesting
198196 static FileDescriptorFactory create (String address , String ... cmd ) throws IOException {
199- final FileDescriptorFactory result = new FileDescriptorFactory ( address );
200-
197+ // must be created before the process
198+ final LocalServerSocket socket = new LocalServerSocket ( address );
201199 try {
202200 final Process shell = new ProcessBuilder (cmd )
203201 .redirectErrorStream (true )
204202 .start ();
205203
206- result .startServer (shell );
204+ final FileDescriptorFactory result = new FileDescriptorFactory (shell , socket );
205+
206+ result .startServer ();
207207
208208 return result ;
209209 } catch (Throwable t ) {
210- result . close ( );
210+ shut ( socket );
211211
212212 throw t ;
213213 }
214214 }
215215
216216 private final AtomicBoolean closedStatus = new AtomicBoolean (false );
217- private final SynchronousQueue <FdReq > intake = new SynchronousQueue <>();
217+ private final ArrayBlockingQueue <FdReq > intake = new ArrayBlockingQueue <>(1 );
218218 private final SynchronousQueue <FdResp > responses = new SynchronousQueue <>();
219- private PhantomReference f ;
220219
221- private final LocalServerSocket socket ;
220+ final LocalServerSocket serverSocket ;
221+ final Process clientProcess ;
222222
223223 private volatile Server serverThread ;
224224
225- private FileDescriptorFactory (String address ) throws IOException {
226- this .socket = new LocalServerSocket (address );
225+ private FileDescriptorFactory (final Process clientProcess , final LocalServerSocket serverSocket ) {
226+ this .clientProcess = clientProcess ;
227+ this .serverSocket = serverSocket ;
228+
229+ intake .offer (FdReq .PLACEHOLDER );
227230 }
228231
229- private void startServer (Process client ) throws IOException {
230- serverThread = new Server (client , socket );
232+ private void startServer () throws IOException {
233+ serverThread = new Server ();
231234 serverThread .start ();
232235 }
233236
@@ -281,6 +284,7 @@ private void startServer(Process client) throws IOException {
281284
282285 final FdReq request = new FdReq (path , mode );
283286
287+
284288 FdResp response ;
285289 try {
286290 if (intake .offer (request , HELPER_TIMEOUT , TimeUnit .MILLISECONDS )
@@ -310,15 +314,16 @@ private void startServer(Process client) throws IOException {
310314 @ Override
311315 public void close () {
312316 if (!closedStatus .compareAndSet (false , true )) {
313- intake .offer (FdReq .STOP );
317+ shut (clientProcess );
318+ shut (serverSocket );
314319
315- try {
316- socket . close ();
317- } catch ( IOException e ) {
318- logException ( "Failed to close server socket" , e );
319- } finally {
320- if ( serverThread != null )
321- serverThread . interrupt ( );
320+ if ( serverThread != null ) {
321+ serverThread . interrupt ();
322+
323+ do {
324+ intake . clear ();
325+ }
326+ while (! intake . offer ( FdReq . STOP ) );
322327 }
323328 }
324329 }
@@ -328,27 +333,21 @@ public boolean isClosed() {
328333 }
329334
330335 private final class Server extends Thread {
331- private final Process client ;
332- private final LocalServerSocket serverSocket ;
333-
334336 private final ByteBuffer statusMsg = ByteBuffer .allocate (512 ).order (ByteOrder .nativeOrder ());
335337
336338 int lastClientReadCount ;
337339
338- Server (Process client , LocalServerSocket serverSocket ) throws IOException {
340+ Server () throws IOException {
339341 super ("fd receiver" );
340-
341- this .client = client ;
342- this .serverSocket = serverSocket ;
343342 }
344343
345344 @ Override
346345 public void run () {
347- try (ReadableByteChannel clientOutput = Channels .newChannel (client .getInputStream ());
346+ try (ReadableByteChannel clientOutput = Channels .newChannel (clientProcess .getInputStream ());
348347 Closeable c = new CloseableSocket (serverSocket ))
349348 {
350349 try {
351- initializeAndHandleRequests (readHelperPid (clientOutput ), serverSocket );
350+ initializeAndHandleRequests (readHelperPid (clientOutput ));
352351 } finally {
353352 try {
354353 do {
@@ -367,7 +366,9 @@ public void run() {
367366 FdCompat .set (closedStatus );
368367
369368 try {
370- client .waitFor ();
369+ setName ("BUG: Waiting for su process, which won't quit" );
370+
371+ clientProcess .waitFor ();
371372 } catch (InterruptedException e ) {
372373 Thread .currentThread ().interrupt ();
373374 }
@@ -389,9 +390,9 @@ private int readHelperPid(ReadableByteChannel clientOutput) throws IOException {
389390 return Integer .valueOf (m .group (1 ));
390391 }
391392
392- private void initializeAndHandleRequests (int helperPid , LocalServerSocket socket ) throws Exception {
393+ private void initializeAndHandleRequests (int helperPid ) throws Exception {
393394 while (!isInterrupted ()) {
394- try (LocalSocket localSocket = socket .accept ())
395+ try (LocalSocket localSocket = serverSocket .accept ())
395396 {
396397 final int socketPid = localSocket .getPeerCredentials ().getPid ();
397398 if (socketPid != helperPid )
@@ -430,6 +431,9 @@ private void initializeAndHandleRequests(int helperPid, LocalServerSocket socket
430431 }
431432 }
432433
434+ if (intake .take () == FdReq .STOP )
435+ return ;
436+
433437 processRequestsUntilStopped (localSocket , status , clientTty );
434438
435439 break ;
@@ -442,7 +446,7 @@ private void initializeAndHandleRequests(int helperPid, LocalServerSocket socket
442446 private void processRequestsUntilStopped (LocalSocket fdrecv , ReadableByteChannel status , Writer control ) throws IOException , InterruptedException {
443447 FdReq fileOps ;
444448
445- while ((fileOps = intake .take ()) != FdReq .STOP ) {
449+ while ((fileOps = intake .poll ()) != FdReq .STOP ) {
446450 FdResp response = null ;
447451
448452 try {
@@ -511,9 +515,41 @@ private static void logException(String explanation, Exception err) {
511515 }
512516 }
513517
518+ private static void shut (Closeable closeable ) {
519+ try {
520+ if (closeable != null )
521+ closeable .close ();
522+ } catch (IOException e ) {
523+ // just as planned
524+ }
525+ }
526+
527+ private static void shut (LocalServerSocket sock ) {
528+ try {
529+ if (sock != null )
530+ sock .close ();
531+ } catch (IOException e ) {
532+ logException ("Failed to close server socket" , e );
533+ }
534+ }
535+
536+ private static void shut (Process proc ) {
537+ try {
538+ if (proc != null ) {
539+ shut (proc .getInputStream ());
540+ shut (proc .getOutputStream ());
541+ proc .destroy ();
542+ }
543+ } catch (Exception e ) {
544+ // just as planned
545+ }
546+ }
547+
514548 private static final class FdReq {
515549 static FdReq STOP = new FdReq (null , 0 );
516550
551+ static FdReq PLACEHOLDER = new FdReq (null , 0 );
552+
517553 final String fileName ;
518554 final int mode ;
519555
0 commit comments