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