OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.base; | |
6 | |
7 import android.app.Service; | |
8 import android.content.Intent; | |
9 import android.os.Handler; | |
10 import android.os.IBinder; | |
11 import android.os.Process; | |
12 | |
13 import org.chromium.base.annotations.CalledByNative; | |
14 import org.chromium.base.annotations.JNINamespace; | |
15 import org.chromium.base.annotations.SuppressFBWarnings; | |
16 import org.chromium.base.library_loader.LibraryLoader; | |
17 import org.chromium.base.library_loader.LibraryProcessType; | |
18 import org.chromium.base.library_loader.ProcessInitException; | |
19 | |
20 import javax.annotation.concurrent.GuardedBy; | |
21 | |
22 /** | |
23 * The service implementation used to host all multiprocess test client code. | |
24 */ | |
25 @JNINamespace("base::android") | |
26 public class MultiprocessTestClientService extends Service { | |
27 private static final String TAG = "cr_TestClient"; | |
28 | |
29 private static boolean sAlreadyInitialized = false; | |
30 | |
31 private final Handler mHandler = new Handler(); | |
32 | |
33 private final Object mResultLock = new Object(); | |
34 | |
35 @GuardedBy("mResultLock") | |
36 private MainReturnCodeResult mResult; | |
Robert Sesek
2016/12/20 20:44:34
Could you use a Future<MainResultCodeResult> inste
Jay Civelli
2016/12/20 23:07:26
Do you mean having a FutureTask<MainResultCodeResu
Robert Sesek
2016/12/21 19:26:07
Ah, I see your point. I was actually thinking of C
| |
37 | |
38 private final ITestClient.Stub mBinder = new ITestClient.Stub() { | |
39 @Override | |
40 public int launch(final String[] commandLine, FileDescriptorInfo[] fdsTo Map) { | |
41 final int[] fdIds = new int[fdsToMap.length]; | |
42 final int[] fdFds = new int[fdsToMap.length]; | |
43 for (int i = 0; i < fdsToMap.length; i++) { | |
44 fdIds[i] = fdsToMap[i].id; | |
45 // Take ownership of the file descriptor so they outlive the Fil eDescriptorInfo | |
46 // instances. Native code will own them. | |
47 fdFds[i] = fdsToMap[i].fd.detachFd(); | |
48 } | |
49 // Don't run main directly, it would block and the response would no t be returned. | |
50 // We post to the main thread as this thread does not have a Looper. | |
51 mHandler.post(new Runnable() { | |
52 @Override | |
53 public void run() { | |
54 nativeRunMain(commandLine, fdIds, fdFds); | |
55 } | |
56 }); | |
57 return Process.myPid(); | |
58 } | |
59 | |
60 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE") | |
61 @Override | |
62 public MainReturnCodeResult waitForMainToReturn(int timeoutMs) { | |
63 synchronized (mResultLock) { | |
64 while (mResult == null) { | |
65 try { | |
66 mResultLock.wait(timeoutMs); | |
67 } catch (InterruptedException ie) { | |
68 continue; | |
69 } | |
70 // Check if we timed-out. | |
71 if (mResult == null) { | |
72 Log.e(TAG, "Failed to wait for main return value."); | |
73 return new MainReturnCodeResult(0, true /* timed-out */) ; | |
74 } | |
75 } | |
76 return mResult; | |
77 } | |
78 } | |
79 | |
80 @SuppressFBWarnings("DM_EXIT") | |
81 @Override | |
82 public boolean forceStopSynchronous(int exitCode) { | |
83 System.exit(exitCode); | |
84 return true; | |
85 } | |
86 | |
87 @SuppressFBWarnings("DM_EXIT") | |
88 @Override | |
89 public void forceStop(int exitCode) { | |
90 System.exit(exitCode); | |
91 } | |
92 }; | |
93 | |
94 @SuppressFBWarnings("DM_EXIT") | |
95 @Override | |
96 public void onCreate() { | |
97 super.onCreate(); | |
98 | |
99 if (sAlreadyInitialized) { | |
100 // 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 | |
102 // 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. | |
104 // This is not ideal, but there are no clear alternatives at this po int. | |
105 Log.e(TAG, "Service being reused, forcing stoppage."); | |
106 System.exit(0); | |
107 return; | |
108 } | |
109 markInitialized(); | |
110 | |
111 ContextUtils.initApplicationContext(getApplicationContext()); | |
112 | |
113 PathUtils.setPrivateDataDirectorySuffix("chrome_multiprocess_test_client _service"); | |
114 | |
115 loadLibraries(); | |
116 } | |
117 | |
118 @Override | |
119 public IBinder onBind(Intent intent) { | |
120 return mBinder; | |
121 } | |
122 | |
123 private void loadLibraries() { | |
124 try { | |
125 LibraryLoader.get(LibraryProcessType.PROCESS_CHILD).loadNow(); | |
126 } catch (ProcessInitException pie) { | |
127 Log.e(TAG, "Unable to load native libraries.", pie); | |
128 } | |
129 ContextUtils.initApplicationContextForNative(); | |
130 } | |
131 | |
132 @CalledByNative | |
133 private void setMainReturnValue(int result) { | |
134 synchronized (mResultLock) { | |
135 mResult = new MainReturnCodeResult(result, false /* timed-out */); | |
136 mResultLock.notifyAll(); | |
137 } | |
138 } | |
139 | |
140 private static void markInitialized() { | |
Robert Sesek
2016/12/20 20:44:34
This is called exactly once, so inline it?
Jay Civelli
2016/12/20 23:07:26
Is to avoid FindBugs complaining that a static fie
| |
141 sAlreadyInitialized = true; | |
142 } | |
143 | |
144 private native void nativeRunMain(String[] commandLine, int[] fdsToMapIds, i nt[] fdsToMapFds); | |
145 } | |
OLD | NEW |