OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.base; | 5 package org.chromium.base; |
6 | 6 |
7 import android.app.Service; | 7 import android.app.Service; |
8 import android.content.Intent; | 8 import android.content.Intent; |
| 9 import android.os.Bundle; |
9 import android.os.Handler; | 10 import android.os.Handler; |
10 import android.os.IBinder; | 11 import android.os.IBinder; |
| 12 import android.os.Parcelable; |
11 import android.os.Process; | 13 import android.os.Process; |
| 14 import android.os.RemoteException; |
12 | 15 |
13 import org.chromium.base.annotations.SuppressFBWarnings; | 16 import org.chromium.base.annotations.SuppressFBWarnings; |
14 import org.chromium.base.library_loader.LibraryLoader; | 17 import org.chromium.base.library_loader.LibraryLoader; |
15 import org.chromium.base.library_loader.LibraryProcessType; | 18 import org.chromium.base.library_loader.LibraryProcessType; |
16 import org.chromium.base.library_loader.ProcessInitException; | 19 import org.chromium.base.library_loader.ProcessInitException; |
17 import org.chromium.base.process_launcher.FileDescriptorInfo; | 20 import org.chromium.base.process_launcher.FileDescriptorInfo; |
18 import org.chromium.native_test.MainRunner; | 21 import org.chromium.native_test.MainRunner; |
19 | 22 |
20 import javax.annotation.concurrent.GuardedBy; | 23 import javax.annotation.concurrent.GuardedBy; |
21 | 24 |
22 /** | 25 /** |
23 * The service implementation used to host all multiprocess test client code. | 26 * The service implementation used to host all multiprocess test client code. |
24 */ | 27 */ |
25 public class MultiprocessTestClientService extends Service { | 28 public class MultiprocessTestClientService extends Service { |
26 private static final String TAG = "cr_TestClient"; | 29 private static final String TAG = "cr_TestClient"; |
27 | 30 |
28 private static boolean sAlreadyInitialized = false; | 31 private static boolean sAlreadyInitialized = false; |
29 | 32 |
30 private final Handler mHandler = new Handler(); | 33 private final Handler mHandler = new Handler(); |
31 | 34 |
32 private final Object mResultLock = new Object(); | 35 private final Object mResultLock = new Object(); |
33 | 36 |
34 @GuardedBy("mResultLock") | 37 @GuardedBy("mResultLock") |
35 private MainReturnCodeResult mResult; | 38 private MainReturnCodeResult mResult; |
36 | 39 |
37 private final ITestClient.Stub mBinder = new ITestClient.Stub() { | 40 private final ITestController.Stub mTestController = new ITestController.Stu
b() { |
38 @Override | |
39 public int launch(final String[] commandLine, FileDescriptorInfo[] fdsTo
Map) { | |
40 final int[] fdKeys = new int[fdsToMap.length]; | |
41 final int[] fdFds = new int[fdsToMap.length]; | |
42 for (int i = 0; i < fdsToMap.length; i++) { | |
43 fdKeys[i] = fdsToMap[i].id; | |
44 // Take ownership of the file descriptor so they outlive the Fil
eDescriptorInfo | |
45 // instances. Native code will own them. | |
46 fdFds[i] = fdsToMap[i].fd.detachFd(); | |
47 } | |
48 // Don't run main directly, it would block and the response would no
t be returned. | |
49 // We post to the main thread as this thread does not have a Looper. | |
50 mHandler.post(new Runnable() { | |
51 @Override | |
52 public void run() { | |
53 int result = MainRunner.runMain(commandLine, fdKeys, fdFds); | |
54 setMainReturnValue(result); | |
55 } | |
56 }); | |
57 return Process.myPid(); | |
58 } | |
59 | |
60 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE") | 41 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE") |
61 @Override | 42 @Override |
62 public MainReturnCodeResult waitForMainToReturn(int timeoutMs) { | 43 public MainReturnCodeResult waitForMainToReturn(int timeoutMs) { |
63 synchronized (mResultLock) { | 44 synchronized (mResultLock) { |
64 while (mResult == null) { | 45 while (mResult == null) { |
65 try { | 46 try { |
66 mResultLock.wait(timeoutMs); | 47 mResultLock.wait(timeoutMs); |
67 } catch (InterruptedException ie) { | 48 } catch (InterruptedException ie) { |
68 continue; | 49 continue; |
69 } | 50 } |
(...skipping 14 matching lines...) Expand all Loading... |
84 return true; | 65 return true; |
85 } | 66 } |
86 | 67 |
87 @SuppressFBWarnings("DM_EXIT") | 68 @SuppressFBWarnings("DM_EXIT") |
88 @Override | 69 @Override |
89 public void forceStop(int exitCode) { | 70 public void forceStop(int exitCode) { |
90 System.exit(exitCode); | 71 System.exit(exitCode); |
91 } | 72 } |
92 }; | 73 }; |
93 | 74 |
| 75 private final ITestClient.Stub mBinder = new ITestClient.Stub() { |
| 76 @Override |
| 77 public boolean bindToCaller() { |
| 78 return true; |
| 79 } |
| 80 |
| 81 @Override |
| 82 public int setupConnection(Bundle args, final IBinder callback) { |
| 83 // Required to unparcel FileDescriptorInfo. |
| 84 args.setClassLoader(getApplicationContext().getClassLoader()); |
| 85 |
| 86 final String[] commandLine = |
| 87 args.getStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE
); |
| 88 final Parcelable[] fdInfosAsParcelable = |
| 89 args.getParcelableArray(ChildProcessConstants.EXTRA_FILES); |
| 90 |
| 91 FileDescriptorInfo[] fdsToMap = new FileDescriptorInfo[fdInfosAsParc
elable.length]; |
| 92 System.arraycopy(fdInfosAsParcelable, 0, fdsToMap, 0, fdInfosAsParce
lable.length); |
| 93 |
| 94 final int[] fdKeys = new int[fdsToMap.length]; |
| 95 final int[] fdFds = new int[fdsToMap.length]; |
| 96 for (int i = 0; i < fdsToMap.length; i++) { |
| 97 fdKeys[i] = fdsToMap[i].id; |
| 98 // Take ownership of the file descriptor so they outlive the Fil
eDescriptorInfo |
| 99 // instances. Native code will own them. |
| 100 fdFds[i] = fdsToMap[i].fd.detachFd(); |
| 101 } |
| 102 |
| 103 // Prevent potential deadlocks by letting this method return before
calling back to the |
| 104 // launcher: the childConnected implementation on the launcher side
might block until |
| 105 // this method returns. |
| 106 mHandler.post(new Runnable() { |
| 107 @Override |
| 108 public void run() { |
| 109 try { |
| 110 ITestCallback testCallback = ITestCallback.Stub.asInterf
ace(callback); |
| 111 testCallback.childConnected(mTestController); |
| 112 } catch (RemoteException re) { |
| 113 Log.e(TAG, "Failed to notify parent process of connectio
n."); |
| 114 } |
| 115 } |
| 116 }); |
| 117 |
| 118 // Don't run main directly, it would block and the response would no
t be returned. |
| 119 // We post to the main thread as this thread does not have a Looper. |
| 120 mHandler.post(new Runnable() { |
| 121 @Override |
| 122 public void run() { |
| 123 int result = MainRunner.runMain(commandLine, fdKeys, fdFds); |
| 124 setMainReturnValue(result); |
| 125 } |
| 126 }); |
| 127 |
| 128 return Process.myPid(); |
| 129 } |
| 130 }; |
| 131 |
94 @SuppressFBWarnings("DM_EXIT") | 132 @SuppressFBWarnings("DM_EXIT") |
95 @Override | 133 @Override |
96 public void onCreate() { | 134 public void onCreate() { |
97 super.onCreate(); | 135 super.onCreate(); |
98 | 136 |
99 if (sAlreadyInitialized) { | 137 if (sAlreadyInitialized) { |
100 // The framework controls how services are reused and even though no
thing is bound to a | 138 // The framework controls how services are reused and even though no
thing is bound to a |
101 // service it might be kept around. Since we really want to fork a n
ew process when we | 139 // service it might be kept around. Since we really want to fork a n
ew process when we |
102 // bind, we'll kill the process early when a service is reused, forc
ing the framework to | 140 // bind, we'll kill the process early when a service is reused, forc
ing the framework to |
103 // recreate the service in a new process. | 141 // recreate the service in a new process. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 mResultLock.notifyAll(); | 173 mResultLock.notifyAll(); |
136 } | 174 } |
137 } | 175 } |
138 | 176 |
139 private static void markInitialized() { | 177 private static void markInitialized() { |
140 // We don't set sAlreadyInitialized directly in onCreate to avoid FindBu
gs complaining about | 178 // We don't set sAlreadyInitialized directly in onCreate to avoid FindBu
gs complaining about |
141 // a static member been set from a non-static function. | 179 // a static member been set from a non-static function. |
142 sAlreadyInitialized = true; | 180 sAlreadyInitialized = true; |
143 } | 181 } |
144 } | 182 } |
OLD | NEW |