| 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.content.ComponentName; | 7 import android.content.ComponentName; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.ServiceConnection; | 10 import android.content.ServiceConnection; |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 | 173 |
| 174 public int getPid() { | 174 public int getPid() { |
| 175 return mPid; | 175 return mPid; |
| 176 } | 176 } |
| 177 } | 177 } |
| 178 | 178 |
| 179 /** | 179 /** |
| 180 * Spawns and connects to a child process. | 180 * Spawns and connects to a child process. |
| 181 * May not be called from the main thread. | 181 * May not be called from the main thread. |
| 182 * | 182 * |
| 183 * @param context context used to obtain the application context. | |
| 184 * @param commandLine the child process command line argv. | 183 * @param commandLine the child process command line argv. |
| 185 * @return the PID of the started process or 0 if the process could not be s
tarted. | 184 * @return the PID of the started process or 0 if the process could not be s
tarted. |
| 186 */ | 185 */ |
| 187 @CalledByNative | 186 @CalledByNative |
| 188 private static int launchClient(final Context context, final String[] comman
dLine, | 187 private static int launchClient( |
| 189 final FileDescriptorInfo[] filesToMap) { | 188 final String[] commandLine, final FileDescriptorInfo[] filesToMap) { |
| 190 if (ThreadUtils.runningOnUiThread()) { | 189 if (ThreadUtils.runningOnUiThread()) { |
| 191 // This can't be called on the main thread as the native side will b
lock until | 190 // This can't be called on the main thread as the native side will b
lock until |
| 192 // onServiceConnected above is called, which cannot happen if the ma
in thread is | 191 // onServiceConnected above is called, which cannot happen if the ma
in thread is |
| 193 // blocked. | 192 // blocked. |
| 194 throw new RuntimeException("launchClient cannot be called on the mai
n thread"); | 193 throw new RuntimeException("launchClient cannot be called on the mai
n thread"); |
| 195 } | 194 } |
| 196 | 195 |
| 197 ClientServiceConnection connection = | 196 ClientServiceConnection connection = |
| 198 sConnectionAllocator.allocateConnection(commandLine, filesToMap)
; | 197 sConnectionAllocator.allocateConnection(commandLine, filesToMap)
; |
| 199 Intent intent = new Intent(); | 198 Intent intent = new Intent(); |
| 200 String className = connection.getServiceClassName(); | 199 String className = connection.getServiceClassName(); |
| 201 intent.setComponent(new ComponentName(context.getPackageName(), classNam
e)); | 200 String packageName = ContextUtils.getApplicationContext().getPackageName
(); |
| 202 if (!context.bindService( | 201 intent.setComponent(new ComponentName(packageName, className)); |
| 202 if (!ContextUtils.getApplicationContext().bindService( |
| 203 intent, connection, Context.BIND_AUTO_CREATE | Context.BIND_
IMPORTANT)) { | 203 intent, connection, Context.BIND_AUTO_CREATE | Context.BIND_
IMPORTANT)) { |
| 204 Log.e(TAG, "Failed to bind service: " + context.getPackageName() + "
." + className); | 204 Log.e(TAG, "Failed to bind service: " + packageName + "." + classNam
e); |
| 205 sConnectionAllocator.freeConnection(connection); | 205 sConnectionAllocator.freeConnection(connection); |
| 206 return 0; | 206 return 0; |
| 207 } | 207 } |
| 208 | 208 |
| 209 connection.waitForConnection(); | 209 connection.waitForConnection(); |
| 210 | 210 |
| 211 return connection.getPid(); | 211 return connection.getPid(); |
| 212 } | 212 } |
| 213 | 213 |
| 214 /** | 214 /** |
| 215 * Blocks until the main method invoked by a previous call to launchClient t
erminates or until | 215 * Blocks until the main method invoked by a previous call to launchClient t
erminates or until |
| 216 * the specified time-out expires. | 216 * the specified time-out expires. |
| 217 * Returns immediately if main has already returned. | 217 * Returns immediately if main has already returned. |
| 218 * @param context context used to obtain the application context. | |
| 219 * @param pid the process ID that was returned by the call to launchClient | 218 * @param pid the process ID that was returned by the call to launchClient |
| 220 * @param timeoutMs the timeout in milliseconds after which the method retur
ns even if main has | 219 * @param timeoutMs the timeout in milliseconds after which the method retur
ns even if main has |
| 221 * not returned. | 220 * not returned. |
| 222 * @return the return code returned by the main method or whether it timed-o
ut. | 221 * @return the return code returned by the main method or whether it timed-o
ut. |
| 223 */ | 222 */ |
| 224 @CalledByNative | 223 @CalledByNative |
| 225 private static MainReturnCodeResult waitForMainToReturn( | 224 private static MainReturnCodeResult waitForMainToReturn(int pid, int timeout
Ms) { |
| 226 Context context, int pid, int timeoutMs) { | |
| 227 ClientServiceConnection connection = sConnectionAllocator.getConnectionB
yPid(pid); | 225 ClientServiceConnection connection = sConnectionAllocator.getConnectionB
yPid(pid); |
| 228 if (connection == null) { | 226 if (connection == null) { |
| 229 Log.e(TAG, "waitForMainToReturn called on unknown connection for pid
" + pid); | 227 Log.e(TAG, "waitForMainToReturn called on unknown connection for pid
" + pid); |
| 230 return null; | 228 return null; |
| 231 } | 229 } |
| 232 try { | 230 try { |
| 233 return connection.getService().waitForMainToReturn(timeoutMs); | 231 return connection.getService().waitForMainToReturn(timeoutMs); |
| 234 } catch (RemoteException e) { | 232 } catch (RemoteException e) { |
| 235 Log.e(TAG, "Remote call to waitForMainToReturn failed."); | 233 Log.e(TAG, "Remote call to waitForMainToReturn failed."); |
| 236 return null; | 234 return null; |
| 237 } finally { | 235 } finally { |
| 238 freeConnection(context, connection); | 236 freeConnection(connection); |
| 239 } | 237 } |
| 240 } | 238 } |
| 241 | 239 |
| 242 @CalledByNative | 240 @CalledByNative |
| 243 private static boolean terminate(Context context, int pid, int exitCode, boo
lean wait) { | 241 private static boolean terminate(int pid, int exitCode, boolean wait) { |
| 244 ClientServiceConnection connection = sConnectionAllocator.getConnectionB
yPid(pid); | 242 ClientServiceConnection connection = sConnectionAllocator.getConnectionB
yPid(pid); |
| 245 if (connection == null) { | 243 if (connection == null) { |
| 246 Log.e(TAG, "terminate called on unknown connection for pid " + pid); | 244 Log.e(TAG, "terminate called on unknown connection for pid " + pid); |
| 247 return false; | 245 return false; |
| 248 } | 246 } |
| 249 try { | 247 try { |
| 250 if (wait) { | 248 if (wait) { |
| 251 connection.getService().forceStopSynchronous(exitCode); | 249 connection.getService().forceStopSynchronous(exitCode); |
| 252 } else { | 250 } else { |
| 253 connection.getService().forceStop(exitCode); | 251 connection.getService().forceStop(exitCode); |
| 254 } | 252 } |
| 255 } catch (RemoteException e) { | 253 } catch (RemoteException e) { |
| 256 // We expect this failure, since the forceStop's service implementat
ion calls | 254 // We expect this failure, since the forceStop's service implementat
ion calls |
| 257 // System.exit(). | 255 // System.exit(). |
| 258 } finally { | 256 } finally { |
| 259 freeConnection(context, connection); | 257 freeConnection(connection); |
| 260 } | 258 } |
| 261 return true; | 259 return true; |
| 262 } | 260 } |
| 263 | 261 |
| 264 private static void freeConnection(Context context, ClientServiceConnection
connection) { | 262 private static void freeConnection(ClientServiceConnection connection) { |
| 265 context.unbindService(connection); | 263 ContextUtils.getApplicationContext().unbindService(connection); |
| 266 sConnectionAllocator.freeConnection(connection); | 264 sConnectionAllocator.freeConnection(connection); |
| 267 } | 265 } |
| 268 | 266 |
| 269 /** Does not take ownership of of fds. */ | 267 /** Does not take ownership of of fds. */ |
| 270 @CalledByNative | 268 @CalledByNative |
| 271 private static FileDescriptorInfo[] makeFdInfoArray(int[] keys, int[] fds) { | 269 private static FileDescriptorInfo[] makeFdInfoArray(int[] keys, int[] fds) { |
| 272 FileDescriptorInfo[] fdInfos = new FileDescriptorInfo[keys.length]; | 270 FileDescriptorInfo[] fdInfos = new FileDescriptorInfo[keys.length]; |
| 273 for (int i = 0; i < keys.length; i++) { | 271 for (int i = 0; i < keys.length; i++) { |
| 274 FileDescriptorInfo fdInfo = makeFdInfo(keys[i], fds[i]); | 272 FileDescriptorInfo fdInfo = makeFdInfo(keys[i], fds[i]); |
| 275 if (fdInfo == null) { | 273 if (fdInfo == null) { |
| 276 Log.e(TAG, "Failed to make file descriptor (" + keys[i] + ", " +
fds[i] + ")."); | 274 Log.e(TAG, "Failed to make file descriptor (" + keys[i] + ", " +
fds[i] + ")."); |
| 277 return null; | 275 return null; |
| 278 } | 276 } |
| 279 fdInfos[i] = fdInfo; | 277 fdInfos[i] = fdInfo; |
| 280 } | 278 } |
| 281 return fdInfos; | 279 return fdInfos; |
| 282 } | 280 } |
| 283 | 281 |
| 284 private static FileDescriptorInfo makeFdInfo(int id, int fd) { | 282 private static FileDescriptorInfo makeFdInfo(int id, int fd) { |
| 285 ParcelFileDescriptor parcelableFd = null; | 283 ParcelFileDescriptor parcelableFd = null; |
| 286 try { | 284 try { |
| 287 parcelableFd = ParcelFileDescriptor.fromFd(fd); | 285 parcelableFd = ParcelFileDescriptor.fromFd(fd); |
| 288 } catch (IOException e) { | 286 } catch (IOException e) { |
| 289 Log.e(TAG, "Invalid FD provided for process connection, aborting con
nection.", e); | 287 Log.e(TAG, "Invalid FD provided for process connection, aborting con
nection.", e); |
| 290 return null; | 288 return null; |
| 291 } | 289 } |
| 292 return new FileDescriptorInfo(id, parcelableFd, 0 /* offset */, 0 /* siz
e */); | 290 return new FileDescriptorInfo(id, parcelableFd, 0 /* offset */, 0 /* siz
e */); |
| 293 } | 291 } |
| 294 } | 292 } |
| OLD | NEW |