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.SuppressFBWarnings; |
| 14 import org.chromium.base.library_loader.LibraryLoader; |
| 15 import org.chromium.base.library_loader.LibraryProcessType; |
| 16 import org.chromium.base.library_loader.ProcessInitException; |
| 17 import org.chromium.native_test.MainRunner; |
| 18 |
| 19 import javax.annotation.concurrent.GuardedBy; |
| 20 |
| 21 /** |
| 22 * The service implementation used to host all multiprocess test client code. |
| 23 */ |
| 24 public class MultiprocessTestClientService extends Service { |
| 25 private static final String TAG = "cr_TestClient"; |
| 26 |
| 27 private static boolean sAlreadyInitialized = false; |
| 28 |
| 29 private final Handler mHandler = new Handler(); |
| 30 |
| 31 private final Object mResultLock = new Object(); |
| 32 |
| 33 @GuardedBy("mResultLock") |
| 34 private MainReturnCodeResult mResult; |
| 35 |
| 36 private final ITestClient.Stub mBinder = new ITestClient.Stub() { |
| 37 @Override |
| 38 public int launch(final String[] commandLine, FileDescriptorInfo[] fdsTo
Map) { |
| 39 final int[] fdKeys = new int[fdsToMap.length]; |
| 40 final int[] fdFds = new int[fdsToMap.length]; |
| 41 for (int i = 0; i < fdsToMap.length; i++) { |
| 42 fdKeys[i] = fdsToMap[i].key; |
| 43 // Take ownership of the file descriptor so they outlive the Fil
eDescriptorInfo |
| 44 // instances. Native code will own them. |
| 45 fdFds[i] = fdsToMap[i].fd.detachFd(); |
| 46 } |
| 47 // Don't run main directly, it would block and the response would no
t be returned. |
| 48 // We post to the main thread as this thread does not have a Looper. |
| 49 mHandler.post(new Runnable() { |
| 50 @Override |
| 51 public void run() { |
| 52 int result = MainRunner.runMain(commandLine, fdKeys, fdFds); |
| 53 setMainReturnValue(result); |
| 54 } |
| 55 }); |
| 56 return Process.myPid(); |
| 57 } |
| 58 |
| 59 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE") |
| 60 @Override |
| 61 public MainReturnCodeResult waitForMainToReturn(int timeoutMs) { |
| 62 synchronized (mResultLock) { |
| 63 while (mResult == null) { |
| 64 try { |
| 65 mResultLock.wait(timeoutMs); |
| 66 } catch (InterruptedException ie) { |
| 67 continue; |
| 68 } |
| 69 // Check if we timed-out. |
| 70 if (mResult == null) { |
| 71 Log.e(TAG, "Failed to wait for main return value."); |
| 72 return new MainReturnCodeResult(0, true /* timed-out */)
; |
| 73 } |
| 74 } |
| 75 return mResult; |
| 76 } |
| 77 } |
| 78 |
| 79 @SuppressFBWarnings("DM_EXIT") |
| 80 @Override |
| 81 public boolean forceStopSynchronous(int exitCode) { |
| 82 System.exit(exitCode); |
| 83 return true; |
| 84 } |
| 85 |
| 86 @SuppressFBWarnings("DM_EXIT") |
| 87 @Override |
| 88 public void forceStop(int exitCode) { |
| 89 System.exit(exitCode); |
| 90 } |
| 91 }; |
| 92 |
| 93 @SuppressFBWarnings("DM_EXIT") |
| 94 @Override |
| 95 public void onCreate() { |
| 96 super.onCreate(); |
| 97 |
| 98 if (sAlreadyInitialized) { |
| 99 // The framework controls how services are reused and even though no
thing is bound to a |
| 100 // service it might be kept around. Since we really want to fork a n
ew process when we |
| 101 // bind, we'll kill the process early when a service is reused, forc
ing the framework to |
| 102 // recreate the service in a new process. |
| 103 // This is not ideal, but there are no clear alternatives at this po
int. |
| 104 Log.e(TAG, "Service being reused, forcing stoppage."); |
| 105 System.exit(0); |
| 106 return; |
| 107 } |
| 108 markInitialized(); |
| 109 |
| 110 ContextUtils.initApplicationContext(getApplicationContext()); |
| 111 |
| 112 PathUtils.setPrivateDataDirectorySuffix("chrome_multiprocess_test_client
_service"); |
| 113 |
| 114 loadLibraries(); |
| 115 } |
| 116 |
| 117 @Override |
| 118 public IBinder onBind(Intent intent) { |
| 119 return mBinder; |
| 120 } |
| 121 |
| 122 private void loadLibraries() { |
| 123 try { |
| 124 LibraryLoader.get(LibraryProcessType.PROCESS_CHILD).loadNow(); |
| 125 } catch (ProcessInitException pie) { |
| 126 Log.e(TAG, "Unable to load native libraries.", pie); |
| 127 } |
| 128 ContextUtils.initApplicationContextForNative(); |
| 129 } |
| 130 |
| 131 private void setMainReturnValue(int result) { |
| 132 synchronized (mResultLock) { |
| 133 mResult = new MainReturnCodeResult(result, false /* timed-out */); |
| 134 mResultLock.notifyAll(); |
| 135 } |
| 136 } |
| 137 |
| 138 private static void markInitialized() { |
| 139 // We don't set sAlreadyInitialized directly in onCreate to avoid FindBu
gs complaining about |
| 140 // a static member been set from a non-static function. |
| 141 sAlreadyInitialized = true; |
| 142 } |
| 143 } |
OLD | NEW |