1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.content.browser; 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ComponentName; 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.Context; 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.Intent; 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ServiceConnection; 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.AsyncTask; 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Bundle; 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Handler; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.IBinder; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Looper; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.ParcelFileDescriptor; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.IOException; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.concurrent.atomic.AtomicBoolean; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.CalledByNative; 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.CpuFeatures; 247c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles)import org.chromium.base.SysUtils; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.ThreadUtils; 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.app.ChildProcessService; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.common.CommandLine; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.common.IChildProcessCallback; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.common.IChildProcessService; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.common.TraceEvent; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/** 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Manages a connection between the browser activity and a child service. The class is responsible 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * for estabilishing the connection (start()), closing it (stop()) and increasing the priority of 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * the service when it is in active use (between calls to attachAsActive() and detachAsActive()). 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochpublic class ChildProcessConnection { 38d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch /** 39d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * Used to notify the consumer about disconnection of the service. This callback is provided 40d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * earlier than ConnectionCallbacks below, as a child process might die before the connection is 41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * fully set up. 42d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch */ 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface DeathCallback { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void onChildProcessDied(int pid); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch /** 48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * Used to notify the consumer about the connection being established and about out-of-memory 49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * bindings being bound for the connection. "Out-of-memory" bindings are bindings that raise the 50d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * priority of the service process so that it does not get killed by the OS out-of-memory killer 51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * during normal operation (yet it still may get killed under drastic memory pressure). 52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch */ 53d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch interface ConnectionCallbacks { 54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch /** 55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * Called when the connection to the service is established. It will be called before any 56d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * calls to onOomBindingsAdded(), onOomBindingRemoved(). 57d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * @param pid Pid of the child process. 58d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * @param oomBindingCount Number of the out-of-memory bindings bound before the connection 59d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * was established. 60d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch */ 61d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch void onConnected(int pid, int oomBindingCount); 62d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 63d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch /** 64d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * Called when a new out-of-memory binding is bound. 65d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch */ 66d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch void onOomBindingAdded(int pid); 67d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch /** 69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * Called when an out-of-memory binding is unbound. 70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch */ 71d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch void onOomBindingRemoved(int pid); 72d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 73d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Names of items placed in the bind intent or connection bundle. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String EXTRA_COMMAND_LINE = 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "com.google.android.apps.chrome.extra.command_line"; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note the FDs may only be passed in the connection bundle. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String EXTRA_FILES_PREFIX = 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "com.google.android.apps.chrome.extra.extraFile_"; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String EXTRA_FILES_ID_SUFFIX = "_id"; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final String EXTRA_FILES_FD_SUFFIX = "_fd"; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Used to pass the CPU core count to child processes. 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String EXTRA_CPU_COUNT = 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "com.google.android.apps.chrome.extra.cpu_count"; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Used to pass the CPU features mask to child processes. 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String EXTRA_CPU_FEATURES = 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "com.google.android.apps.chrome.extra.cpu_features"; 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private final Context mContext; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private final int mServiceNumber; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final boolean mInSandbox; 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final ChildProcessConnection.DeathCallback mDeathCallback; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final Class<? extends ChildProcessService> mServiceClass; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Synchronization: While most internal flow occurs on the UI thread, the public API 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // (specifically start and stop) may be called from any thread, hence all entry point methods 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // into the class are synchronized on the ChildProcessConnection instance to protect access to 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // these members. But see also the TODO where AsyncBoundServiceConnection is created. 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final Object mUiThreadLock = new Object(); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private IChildProcessService mService = null; 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Set to true when the service connect is finished, even if it fails. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private boolean mServiceConnectComplete = false; 104d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Set to true when the service disconnects, as opposed to being properly closed. This happens 105d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // when the process crashes or gets killed by the system out-of-memory killer. 106d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch private boolean mServiceDisconnected = false; 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private int mPID = 0; // Process ID of the corresponding child process. 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Initial binding protects the newly spawned process from being killed before it is put to use, 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // it is maintained between calls to start() and removeInitialBinding(). 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private ChildServiceConnection mInitialBinding = null; 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Strong binding will make the service priority equal to the priority of the activity. We want 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // the OS to be able to kill background renderers as it kills other background apps, so strong 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // bindings are maintained only for services that are active at the moment (between 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // attachAsActive() and detachAsActive()). 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private ChildServiceConnection mStrongBinding = null; 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Low priority binding maintained in the entire lifetime of the connection, i.e. between calls 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // to start() and stop(). 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private ChildServiceConnection mWaivedBinding = null; 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Incremented on attachAsActive(), decremented on detachAsActive(). 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private int mAttachAsActiveCount = 0; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private static final String TAG = "ChildProcessConnection"; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static class ConnectionParams { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final String[] mCommandLine; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final FileDescriptorInfo[] mFilesToBeMapped; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final IChildProcessCallback mCallback; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 129d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch ConnectionParams(String[] commandLine, FileDescriptorInfo[] filesToBeMapped, 130d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch IChildProcessCallback callback) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mCommandLine = commandLine; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mFilesToBeMapped = filesToBeMapped; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mCallback = callback; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // This is set by the consumer of the class in setupConnection() and is later used in 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // doSetupConnection(), after which the variable is cleared. Therefore this is only valid while 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // the connection is being set up. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private ConnectionParams mConnectionParams; 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 142d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Callbacks used to notify the consumer about connection events. This is also provided in 143d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // setupConnection(), but remains valid after setup. 144d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch private ChildProcessConnection.ConnectionCallbacks mConnectionCallbacks; 145d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private class ChildServiceConnection implements ServiceConnection { 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private boolean mBound = false; 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private final int mBindFlags; 150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch private final boolean mProtectsFromOom; 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 152d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch public ChildServiceConnection(int bindFlags, boolean protectsFromOom) { 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mBindFlags = bindFlags; 154d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mProtectsFromOom = protectsFromOom; 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch boolean bind(String[] commandLine) { 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!mBound) { 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch final Intent intent = createServiceBindIntent(); 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (commandLine != null) { 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch intent.putExtra(EXTRA_COMMAND_LINE, commandLine); 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mBound = mContext.bindService(intent, this, mBindFlags); 164d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (mBound && mProtectsFromOom && mConnectionCallbacks != null) { 165d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mConnectionCallbacks.onOomBindingAdded(getPid()); 166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return mBound; 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void unbind() { 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (mBound) { 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mContext.unbindService(this); 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mBound = false; 175d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // When the process crashes, we stop reporting bindings being unbound (so that their 176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // numbers can be inspected to determine if the process crash could be caused by the 177d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // out-of-memory killing), hence the mServiceDisconnected check below. 178d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (mProtectsFromOom && mConnectionCallbacks != null && !mServiceDisconnected) { 179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mConnectionCallbacks.onOomBindingRemoved(getPid()); 180d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 184bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch boolean isBound() { 185bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch return mBound; 186bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 187bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch @Override 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public void onServiceConnected(ComponentName className, IBinder service) { 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch synchronized(mUiThreadLock) { 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // A flag from the parent class ensures we run the post-connection logic only once 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // (instead of once per each ChildServiceConnection). 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (mServiceConnectComplete) { 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TraceEvent.begin(); 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mServiceConnectComplete = true; 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mService = IChildProcessService.Stub.asInterface(service); 199d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Make sure that the connection parameters have already been provided. If not, 200d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // doConnectionSetup() will be called from setupConnection(). 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (mConnectionParams != null) { 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch doConnectionSetup(); 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TraceEvent.end(); 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Called on the main thread to notify that the child service did not disconnect gracefully. 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch @Override 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public void onServiceDisconnected(ComponentName className) { 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Ensure that the disconnection logic runs only once (instead of once per each 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // ChildServiceConnection). 214d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (mServiceDisconnected) { 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 217d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mServiceDisconnected = true; 218d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch int pid = mPID; // Stash the pid for DeathCallback since stop() will clear it. 219d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch boolean disconnectedWhileBeingSetUp = mConnectionParams != null; 220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=" + pid); 221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch stop(); // We don't want to auto-restart on crash. Let the browser do that. 222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pid != 0) { 223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mDeathCallback.onChildProcessDied(pid); 224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 225d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // TODO(ppi): does anyone know why we need to do that? 226d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (disconnectedWhileBeingSetUp && mConnectionCallbacks != null) { 227d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mConnectionCallbacks.onConnected(0, 0); 228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChildProcessConnection(Context context, int number, boolean inSandbox, 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChildProcessConnection.DeathCallback deathCallback, 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Class<? extends ChildProcessService> serviceClass) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mContext = context; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mServiceNumber = number; 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mInSandbox = inSandbox; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDeathCallback = deathCallback; 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mServiceClass = serviceClass; 240d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mInitialBinding = new ChildServiceConnection(Context.BIND_AUTO_CREATE, true); 241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mStrongBinding = new ChildServiceConnection( 242d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, true); 243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mWaivedBinding = new ChildServiceConnection( 244d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, false); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int getServiceNumber() { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mServiceNumber; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boolean isInSandbox() { 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return mInSandbox; 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IChildProcessService getService() { 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) synchronized(mUiThreadLock) { 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return mService; 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private Intent createServiceBindIntent() { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Intent intent = new Intent(); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) intent.setClassName(mContext, mServiceClass.getName() + mServiceNumber); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) intent.setPackage(mContext.getPackageName()); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return intent; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Starts a connection to an IChildProcessService. This must be followed by a call to 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * setupConnection() to setup the connection parameters. start() and setupConnection() are 271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * separate to allow the client to pass whatever parameters they have available here, and 272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * complete the remainder later while reducing the connection setup latency. 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param commandLine (Optional) Command line for the child process. If omitted, then 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the command line parameters must instead be passed to setupConnection(). 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void start(String[] commandLine) { 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) synchronized(mUiThreadLock) { 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TraceEvent.begin(); 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert !ThreadUtils.runningOnUiThread(); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!mInitialBinding.bind(commandLine)) { 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) onBindFailed(); 283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mWaivedBinding.bind(null); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TraceEvent.end(); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /** 291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Setups the connection after it was started with start(). This method should be called by the 292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * consumer of the class to set up additional connection parameters. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param commandLine (Optional) will be ignored if the command line was already sent in bind() 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param fileToBeMapped a list of file descriptors that should be registered 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param callback Used for status updates regarding this process connection. 296d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * @param connectionCallbacks will notify the consumer about the connection being established 297d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * and the status of the out-of-memory bindings being bound for the connection. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void setupConnection( 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String[] commandLine, 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileDescriptorInfo[] filesToBeMapped, 302d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch IChildProcessCallback processCallback, 303d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch ConnectionCallbacks connectionCallbacks) { 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) synchronized(mUiThreadLock) { 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TraceEvent.begin(); 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert mConnectionParams == null; 307d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mConnectionCallbacks = connectionCallbacks; 308d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, processCallback); 309d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Make sure that the service is already connected. If not, doConnectionSetup() will be 310d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // called from onServiceConnected(). 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mServiceConnectComplete) { 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) doConnectionSetup(); 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TraceEvent.end(); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Terminates the connection to IChildProcessService, closing all bindings. It is safe to call 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * this multiple times. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void stop() { 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) synchronized(mUiThreadLock) { 324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mInitialBinding.unbind(); 325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mStrongBinding.unbind(); 326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mWaivedBinding.unbind(); 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mAttachAsActiveCount = 0; 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mService != null) { 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mService = null; 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mPID = 0; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mConnectionParams = null; 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mServiceConnectComplete = false; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Called on the main thread to notify that the bindService() call failed (returned false). 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private void onBindFailed() { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mServiceConnectComplete = true; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mConnectionParams != null) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) doConnectionSetup(); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 346d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * Called after the connection parameters have been set (in setupConnection()) *and* a 347d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * connection has been established (as signaled by onServiceConnected()) or failed (as signaled 348d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * by onBindFailed(), in this case mService will be null). These two events can happen in any 349d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch * order. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private void doConnectionSetup() { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TraceEvent.begin(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert mServiceConnectComplete && mConnectionParams != null; 354d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 355d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (mService != null) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bundle bundle = new Bundle(); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bundle.putStringArray(EXTRA_COMMAND_LINE, mConnectionParams.mCommandLine); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileDescriptorInfo[] fileInfos = mConnectionParams.mFilesToBeMapped; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParcelFileDescriptor[] parcelFiles = new ParcelFileDescriptor[fileInfos.length]; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < fileInfos.length; i++) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fileInfos[i].mFd == -1) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If someone provided an invalid FD, they are doing something wrong. 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Log.e(TAG, "Invalid FD (id=" + fileInfos[i].mId + ") for process connection, " 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) + "aborting connection."); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String idName = EXTRA_FILES_PREFIX + i + EXTRA_FILES_ID_SUFFIX; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String fdName = EXTRA_FILES_PREFIX + i + EXTRA_FILES_FD_SUFFIX; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fileInfos[i].mAutoClose) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Adopt the FD, it will be closed when we close the ParcelFileDescriptor. 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parcelFiles[i] = ParcelFileDescriptor.adoptFd(fileInfos[i].mFd); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parcelFiles[i] = ParcelFileDescriptor.fromFd(fileInfos[i].mFd); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch(IOException e) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Log.e(TAG, 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Invalid FD provided for process connection, aborting connection.", 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bundle.putParcelable(fdName, parcelFiles[i]); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bundle.putInt(idName, fileInfos[i].mId); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Add the CPU properties now. 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bundle.putInt(EXTRA_CPU_COUNT, CpuFeatures.getCount()); 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bundle.putLong(EXTRA_CPU_FEATURES, CpuFeatures.getMask()); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mPID = mService.setupConnection(bundle, mConnectionParams.mCallback); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (android.os.RemoteException re) { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Log.e(TAG, "Failed to setup connection.", re); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 396d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // We proactively close the FDs rather than wait for GC & finalizer. 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ParcelFileDescriptor parcelFile : parcelFiles) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parcelFile != null) parcelFile.close(); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (IOException ioe) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Log.w(TAG, "Failed to close FD.", ioe); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mConnectionParams = null; 406d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 407d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (mConnectionCallbacks != null) { 408d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Number of out-of-memory bindings bound before the connection was set up. 409d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch int oomBindingCount = 410d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch (mInitialBinding.isBound() ? 1 : 0) + (mStrongBinding.isBound() ? 1 : 0); 411d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch mConnectionCallbacks.onConnected(getPid(), oomBindingCount); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TraceEvent.end(); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 416bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch private static final long REMOVE_INITIAL_BINDING_DELAY_MILLIS = 1 * 1000; // One second. 417bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /** 419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Called to remove the strong binding estabilished when the connection was started. It is safe 420bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch * to call this multiple times. The binding is removed after a fixed delay period so that the 421bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch * renderer will not be killed immediately after the call. 422eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void removeInitialBinding() { 424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch synchronized(mUiThreadLock) { 425bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch if (!mInitialBinding.isBound()) { 426bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch // While it is safe to post and execute the unbinding multiple times, we prefer to 427bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch // avoid spamming the message queue. 428bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch return; 429bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 431bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch ThreadUtils.postOnUiThreadDelayed(new Runnable() { 432bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch @Override 433bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch public void run() { 434bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch synchronized(mUiThreadLock) { 435bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch mInitialBinding.unbind(); 436bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 437bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 438bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch }, REMOVE_INITIAL_BINDING_DELAY_MILLIS); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 442eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Called when the service becomes active, ie important to the caller. This is handled by 443eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * setting up a binding that will make the service as important as the main process. We allow 444eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * callers to indicate the same connection as active multiple times. Instead of maintaining 445eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * multiple bindings, we count the requests and unbind when the count drops to zero. 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 447eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void attachAsActive() { 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) synchronized(mUiThreadLock) { 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mService == null) { 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "The connection is not bound for " + mPID); 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (mAttachAsActiveCount == 0) { 454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mStrongBinding.bind(null); 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mAttachAsActiveCount++; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4607c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles) private static final long DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS = 5 * 1000; // Five seconds. 461bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 4637c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles) * Called when the service is no longer considered active. For devices that are not considered 4647c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles) * low memory the actual binding is removed after a fixed delay period so that the renderer will 4657c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles) * not be killed immediately after the call. We don't delay the unbinding for low memory devices 4667c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles) * to avoid putting the OS there on strain of having multiple renderers it can't kill. 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void detachAsActive() { 469bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch ThreadUtils.postOnUiThreadDelayed(new Runnable() { 470bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch @Override 471bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch public void run() { 472bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch synchronized(mUiThreadLock) { 473bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch if (mService == null) { 474bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch Log.w(TAG, "The connection is not bound for " + mPID); 475bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch return; 476bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 477bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch assert mAttachAsActiveCount > 0; 478bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch mAttachAsActiveCount--; 479bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch if (mAttachAsActiveCount == 0) { 480bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch mStrongBinding.unbind(); 481bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 482bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch } 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4847c720b7466665b17575e0fd6976f9321c6bff489Torne (Richard Coles) }, SysUtils.isLowEndDevice() ? 0 : DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return The connection PID, or 0 if not yet connected. 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 490d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch int getPid() { 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) synchronized(mUiThreadLock) { 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return mPID; 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 496