blob: a9ee41162ae1ba0ae36617f24374ddd6617cde08 [file] [log] [blame]
Todd Kennedyb8a279e2015-11-18 09:59:47 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.pm;
18
Todd Kennedy1fb34042017-03-01 13:56:58 -080019import android.app.IInstantAppResolver;
20import android.app.InstantAppResolverService;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080021import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
Todd Kennedy1fb34042017-03-01 13:56:58 -080025import android.content.pm.InstantAppResolveInfo;
Tony Makf2645402017-05-12 16:11:43 +010026import android.os.Binder;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080027import android.os.Build;
28import android.os.Bundle;
Todd Kennedy01ad0c72016-11-11 15:33:12 -080029import android.os.Handler;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080030import android.os.IBinder;
Todd Kennedy16c3a3e2017-04-03 12:03:35 -070031import android.os.IBinder.DeathRecipient;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080032import android.os.IRemoteCallback;
33import android.os.RemoteException;
34import android.os.SystemClock;
35import android.os.UserHandle;
Todd Kennedy7cf918e2017-04-10 15:10:56 -070036import android.util.Slog;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080037import android.util.TimedRemoteCaller;
38
Todd Kennedy46b4f2b2017-04-21 12:20:03 -070039import com.android.internal.annotations.GuardedBy;
Jeff Sharkey850c83e2016-11-09 12:25:44 -070040
Todd Kennedyb8a279e2015-11-18 09:59:47 -080041import java.util.ArrayList;
42import java.util.List;
Todd Kennedy34f5b422017-05-03 16:38:44 -070043import java.util.NoSuchElementException;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080044import java.util.concurrent.TimeoutException;
45
46/**
Patrick Baumann43c97a02018-01-31 20:09:03 +000047 * Represents a remote instant app resolver. It is responsible for binding to the remote
Todd Kennedyb8a279e2015-11-18 09:59:47 -080048 * service and handling all interactions in a timely manner.
49 * @hide
50 */
Patrick Baumann43c97a02018-01-31 20:09:03 +000051final class InstantAppResolverConnection implements DeathRecipient {
Todd Kennedy7cf918e2017-04-10 15:10:56 -070052 private static final String TAG = "PackageManager";
Todd Kennedyb8a279e2015-11-18 09:59:47 -080053 // This is running in a critical section and the timeout must be sufficiently low
54 private static final long BIND_SERVICE_TIMEOUT_MS =
Jeff Sharkey5ab02432017-06-27 11:01:36 -060055 Build.IS_ENG ? 500 : 300;
Todd Kennedy46b4f2b2017-04-21 12:20:03 -070056 private static final long CALL_SERVICE_TIMEOUT_MS =
Jeff Sharkey5ab02432017-06-27 11:01:36 -060057 Build.IS_ENG ? 200 : 100;
Patrick Baumann43c97a02018-01-31 20:09:03 +000058 private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080059
60 private final Object mLock = new Object();
Patrick Baumann43c97a02018-01-31 20:09:03 +000061 private final GetInstantAppResolveInfoCaller mGetInstantAppResolveInfoCaller =
62 new GetInstantAppResolveInfoCaller();
Todd Kennedyb8a279e2015-11-18 09:59:47 -080063 private final ServiceConnection mServiceConnection = new MyServiceConnection();
64 private final Context mContext;
65 /** Intent used to bind to the service */
66 private final Intent mIntent;
67
Snild Dolkowe2612eb2017-06-14 09:57:36 +020068 private static final int STATE_IDLE = 0; // no bind operation is ongoing
69 private static final int STATE_BINDING = 1; // someone is binding and waiting
70 private static final int STATE_PENDING = 2; // a bind is pending, but the caller is not waiting
71
Todd Kennedy46b4f2b2017-04-21 12:20:03 -070072 @GuardedBy("mLock")
Snild Dolkowe2612eb2017-06-14 09:57:36 +020073 private int mBindState = STATE_IDLE;
Todd Kennedy46b4f2b2017-04-21 12:20:03 -070074 @GuardedBy("mLock")
Todd Kennedy1fb34042017-03-01 13:56:58 -080075 private IInstantAppResolver mRemoteInstance;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080076
Patrick Baumann43c97a02018-01-31 20:09:03 +000077 public InstantAppResolverConnection(
Todd Kennedy02a6b732017-04-05 14:24:58 -070078 Context context, ComponentName componentName, String action) {
Todd Kennedyb8a279e2015-11-18 09:59:47 -080079 mContext = context;
Todd Kennedy02a6b732017-04-05 14:24:58 -070080 mIntent = new Intent(action).setComponent(componentName);
Todd Kennedyb8a279e2015-11-18 09:59:47 -080081 }
82
Patrick Baumann577d4022018-01-31 16:55:10 +000083 public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(Intent sanitizedIntent,
84 int hashPrefix[], String token) throws ConnectionException {
Todd Kennedyb8a279e2015-11-18 09:59:47 -080085 throwIfCalledOnMainThread();
Todd Kennedy46b4f2b2017-04-21 12:20:03 -070086 IInstantAppResolver target = null;
Todd Kennedyb8a279e2015-11-18 09:59:47 -080087 try {
Todd Kennedybdf2a802017-05-08 16:09:42 -070088 try {
89 target = getRemoteInstanceLazy(token);
90 } catch (TimeoutException e) {
91 throw new ConnectionException(ConnectionException.FAILURE_BIND);
92 } catch (InterruptedException e) {
93 throw new ConnectionException(ConnectionException.FAILURE_INTERRUPTED);
94 }
95 try {
Patrick Baumann43c97a02018-01-31 20:09:03 +000096 return mGetInstantAppResolveInfoCaller
97 .getInstantAppResolveInfoList(target, sanitizedIntent, hashPrefix, token);
Todd Kennedybdf2a802017-05-08 16:09:42 -070098 } catch (TimeoutException e) {
Todd Kennedye6393c92017-05-16 15:47:01 -070099 throw new ConnectionException(ConnectionException.FAILURE_CALL);
Todd Kennedybdf2a802017-05-08 16:09:42 -0700100 } catch (RemoteException ignore) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700101 }
Todd Kennedye5195dd2016-10-19 15:29:19 -0700102 } finally {
103 synchronized (mLock) {
104 mLock.notifyAll();
105 }
106 }
107 return null;
108 }
109
Patrick Baumann577d4022018-01-31 16:55:10 +0000110 public final void getInstantAppIntentFilterList(Intent sanitizedIntent, int hashPrefix[],
111 String token, PhaseTwoCallback callback, Handler callbackHandler, final long startTime)
112 throws ConnectionException {
Todd Kennedy01ad0c72016-11-11 15:33:12 -0800113 final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() {
114 @Override
115 public void sendResult(Bundle data) throws RemoteException {
Todd Kennedy1fb34042017-03-01 13:56:58 -0800116 final ArrayList<InstantAppResolveInfo> resolveList =
117 data.getParcelableArrayList(
118 InstantAppResolverService.EXTRA_RESOLVE_INFO);
Patrick Baumann577d4022018-01-31 16:55:10 +0000119 callbackHandler.post(() -> callback.onPhaseTwoResolved(resolveList, startTime));
Todd Kennedy01ad0c72016-11-11 15:33:12 -0800120 }
121 };
Todd Kennedye5195dd2016-10-19 15:29:19 -0700122 try {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700123 getRemoteInstanceLazy(token)
Patrick Baumann577d4022018-01-31 16:55:10 +0000124 .getInstantAppIntentFilterList(sanitizedIntent, hashPrefix, token,
125 remoteCallback);
Todd Kennedybdf2a802017-05-08 16:09:42 -0700126 } catch (TimeoutException e) {
127 throw new ConnectionException(ConnectionException.FAILURE_BIND);
128 } catch (InterruptedException e) {
129 throw new ConnectionException(ConnectionException.FAILURE_INTERRUPTED);
130 } catch (RemoteException ignore) {
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800131 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800132 }
133
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700134 private IInstantAppResolver getRemoteInstanceLazy(String token)
Todd Kennedybdf2a802017-05-08 16:09:42 -0700135 throws ConnectionException, TimeoutException, InterruptedException {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200136 long binderToken = Binder.clearCallingIdentity();
137 try {
138 return bind(token);
139 } finally {
140 Binder.restoreCallingIdentity(binderToken);
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800141 }
142 }
143
Todd Kennedybdf2a802017-05-08 16:09:42 -0700144 private void waitForBindLocked(String token) throws TimeoutException, InterruptedException {
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800145 final long startMillis = SystemClock.uptimeMillis();
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200146 while (mBindState != STATE_IDLE) {
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800147 if (mRemoteInstance != null) {
148 break;
149 }
150 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
151 final long remainingMillis = BIND_SERVICE_TIMEOUT_MS - elapsedMillis;
152 if (remainingMillis <= 0) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700153 throw new TimeoutException("[" + token + "] Didn't bind to resolver in time!");
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800154 }
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700155 mLock.wait(remainingMillis);
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800156 }
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700157 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800158
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200159 private IInstantAppResolver bind(String token)
Todd Kennedybdf2a802017-05-08 16:09:42 -0700160 throws ConnectionException, TimeoutException, InterruptedException {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200161 boolean doUnbind = false;
162 synchronized (mLock) {
163 if (mRemoteInstance != null) {
164 return mRemoteInstance;
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700165 }
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200166
167 if (mBindState == STATE_PENDING) {
168 // there is a pending bind, let's see if we can use it.
Patrick Baumann43c97a02018-01-31 20:09:03 +0000169 if (DEBUG_INSTANT) {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200170 Slog.i(TAG, "[" + token + "] Previous bind timed out; waiting for connection");
171 }
172 try {
173 waitForBindLocked(token);
174 if (mRemoteInstance != null) {
175 return mRemoteInstance;
176 }
177 } catch (TimeoutException e) {
178 // nope, we might have to try a rebind.
179 doUnbind = true;
180 }
181 }
182
183 if (mBindState == STATE_BINDING) {
184 // someone was binding when we called bind(), or they raced ahead while we were
185 // waiting in the PENDING case; wait for their result instead. Last chance!
Patrick Baumann43c97a02018-01-31 20:09:03 +0000186 if (DEBUG_INSTANT) {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200187 Slog.i(TAG, "[" + token + "] Another thread is binding; waiting for connection");
188 }
189 waitForBindLocked(token);
190 // if the other thread's bindService() returned false, we could still have null.
191 if (mRemoteInstance != null) {
192 return mRemoteInstance;
193 }
194 throw new ConnectionException(ConnectionException.FAILURE_BIND);
195 }
196 mBindState = STATE_BINDING; // our time to shine! :)
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700197 }
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200198
199 // only one thread can be here at a time (the one that set STATE_BINDING)
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700200 boolean wasBound = false;
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200201 IInstantAppResolver instance = null;
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700202 try {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200203 if (doUnbind) {
Patrick Baumann43c97a02018-01-31 20:09:03 +0000204 if (DEBUG_INSTANT) {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200205 Slog.i(TAG, "[" + token + "] Previous connection never established; rebinding");
206 }
207 mContext.unbindService(mServiceConnection);
208 }
Patrick Baumann43c97a02018-01-31 20:09:03 +0000209 if (DEBUG_INSTANT) {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200210 Slog.v(TAG, "[" + token + "] Binding to instant app resolver");
211 }
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700212 final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
213 wasBound = mContext
214 .bindServiceAsUser(mIntent, mServiceConnection, flags, UserHandle.SYSTEM);
215 if (wasBound) {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200216 synchronized (mLock) {
217 waitForBindLocked(token);
218 instance = mRemoteInstance;
219 return instance;
220 }
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700221 } else {
222 Slog.w(TAG, "[" + token + "] Failed to bind to: " + mIntent);
Todd Kennedybdf2a802017-05-08 16:09:42 -0700223 throw new ConnectionException(ConnectionException.FAILURE_BIND);
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700224 }
225 } finally {
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200226 synchronized (mLock) {
227 if (wasBound && instance == null) {
228 mBindState = STATE_PENDING;
229 } else {
230 mBindState = STATE_IDLE;
231 }
232 mLock.notifyAll();
233 }
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700234 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800235 }
236
237 private void throwIfCalledOnMainThread() {
238 if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
239 throw new RuntimeException("Cannot invoke on the main thread");
240 }
241 }
242
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700243 @Override
244 public void binderDied() {
Patrick Baumann43c97a02018-01-31 20:09:03 +0000245 if (DEBUG_INSTANT) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700246 Slog.d(TAG, "Binder to instant app resolver died");
Todd Kennedy7cf918e2017-04-10 15:10:56 -0700247 }
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700248 synchronized (mLock) {
249 handleBinderDiedLocked();
250 }
251 }
252
253 private void handleBinderDiedLocked() {
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700254 if (mRemoteInstance != null) {
Todd Kennedy34f5b422017-05-03 16:38:44 -0700255 try {
256 mRemoteInstance.asBinder().unlinkToDeath(this, 0 /*flags*/);
257 } catch (NoSuchElementException ignore) { }
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700258 }
259 mRemoteInstance = null;
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700260 }
261
Todd Kennedy01ad0c72016-11-11 15:33:12 -0800262 /**
263 * Asynchronous callback when results come back from ephemeral resolution phase two.
264 */
265 public abstract static class PhaseTwoCallback {
Todd Kennedy1fb34042017-03-01 13:56:58 -0800266 abstract void onPhaseTwoResolved(
Todd Kennedy50d946c12017-03-17 13:55:38 -0700267 List<InstantAppResolveInfo> instantAppResolveInfoList, long startTime);
Todd Kennedy01ad0c72016-11-11 15:33:12 -0800268 }
269
Todd Kennedybdf2a802017-05-08 16:09:42 -0700270 public static class ConnectionException extends Exception {
271 public static final int FAILURE_BIND = 1;
272 public static final int FAILURE_CALL = 2;
273 public static final int FAILURE_INTERRUPTED = 3;
274
275 public final int failure;
276 public ConnectionException(int _failure) {
277 failure = _failure;
278 }
279 }
280
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800281 private final class MyServiceConnection implements ServiceConnection {
282 @Override
283 public void onServiceConnected(ComponentName name, IBinder service) {
Patrick Baumann43c97a02018-01-31 20:09:03 +0000284 if (DEBUG_INSTANT) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700285 Slog.d(TAG, "Connected to instant app resolver");
Todd Kennedy7cf918e2017-04-10 15:10:56 -0700286 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800287 synchronized (mLock) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700288 mRemoteInstance = IInstantAppResolver.Stub.asInterface(service);
Snild Dolkowe2612eb2017-06-14 09:57:36 +0200289 if (mBindState == STATE_PENDING) {
290 mBindState = STATE_IDLE;
291 }
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700292 try {
Patrick Baumann43c97a02018-01-31 20:09:03 +0000293 service.linkToDeath(InstantAppResolverConnection.this, 0 /*flags*/);
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700294 } catch (RemoteException e) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700295 handleBinderDiedLocked();
Todd Kennedy16c3a3e2017-04-03 12:03:35 -0700296 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800297 mLock.notifyAll();
298 }
299 }
300
301 @Override
302 public void onServiceDisconnected(ComponentName name) {
Patrick Baumann43c97a02018-01-31 20:09:03 +0000303 if (DEBUG_INSTANT) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700304 Slog.d(TAG, "Disconnected from instant app resolver");
Todd Kennedy7cf918e2017-04-10 15:10:56 -0700305 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800306 synchronized (mLock) {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700307 handleBinderDiedLocked();
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800308 }
309 }
310 }
311
Patrick Baumann43c97a02018-01-31 20:09:03 +0000312 private static final class GetInstantAppResolveInfoCaller
Todd Kennedy1fb34042017-03-01 13:56:58 -0800313 extends TimedRemoteCaller<List<InstantAppResolveInfo>> {
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800314 private final IRemoteCallback mCallback;
315
Patrick Baumann43c97a02018-01-31 20:09:03 +0000316 public GetInstantAppResolveInfoCaller() {
Todd Kennedy46b4f2b2017-04-21 12:20:03 -0700317 super(CALL_SERVICE_TIMEOUT_MS);
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800318 mCallback = new IRemoteCallback.Stub() {
319 @Override
320 public void sendResult(Bundle data) throws RemoteException {
Todd Kennedy1fb34042017-03-01 13:56:58 -0800321 final ArrayList<InstantAppResolveInfo> resolveList =
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800322 data.getParcelableArrayList(
Todd Kennedy1fb34042017-03-01 13:56:58 -0800323 InstantAppResolverService.EXTRA_RESOLVE_INFO);
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800324 int sequence =
Todd Kennedy1fb34042017-03-01 13:56:58 -0800325 data.getInt(InstantAppResolverService.EXTRA_SEQUENCE, -1);
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800326 onRemoteMethodResult(resolveList, sequence);
327 }
328 };
329 }
330
Patrick Baumann43c97a02018-01-31 20:09:03 +0000331 public List<InstantAppResolveInfo> getInstantAppResolveInfoList(
Patrick Baumann577d4022018-01-31 16:55:10 +0000332 IInstantAppResolver target, Intent sanitizedIntent, int hashPrefix[], String token)
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800333 throws RemoteException, TimeoutException {
334 final int sequence = onBeforeRemoteCall();
Patrick Baumann577d4022018-01-31 16:55:10 +0000335 target.getInstantAppResolveInfoList(sanitizedIntent, hashPrefix, token, sequence,
336 mCallback);
Todd Kennedye5195dd2016-10-19 15:29:19 -0700337 return getResultTimed(sequence);
338 }
339 }
Todd Kennedyb8a279e2015-11-18 09:59:47 -0800340}