summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2017-04-24 15:37:45 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2017-04-24 15:37:51 +0000
commit4eaeb91e42182cbb5c6ecfa235fd9ef6319bf25c (patch)
tree2b7aa513e4743702158ee674bf7be7110ef2a3b4
parent1ab9119f507d0b85e79d6098bf2055476683afb6 (diff)
parent46b4f2b7956e61cc2d4bc2f086c20ac859d44ba4 (diff)
Merge "fix service binding" into oc-dev
-rw-r--r--core/java/android/app/InstantAppResolverService.java10
-rw-r--r--services/core/java/com/android/server/pm/EphemeralResolverConnection.java132
-rw-r--r--services/core/java/com/android/server/pm/InstantAppResolver.java23
3 files changed, 100 insertions, 65 deletions
diff --git a/core/java/android/app/InstantAppResolverService.java b/core/java/android/app/InstantAppResolverService.java
index 88399e5d6695..c5dc86c79ef9 100644
--- a/core/java/android/app/InstantAppResolverService.java
+++ b/core/java/android/app/InstantAppResolverService.java
@@ -91,6 +91,9 @@ public abstract class InstantAppResolverService extends Service {
@Override
public void getInstantAppResolveInfoList(
int digestPrefix[], String token, int sequence, IRemoteCallback callback) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "[" + token + "] Phase1 called; posting");
+ }
final SomeArgs args = SomeArgs.obtain();
args.arg1 = callback;
args.arg2 = digestPrefix;
@@ -103,6 +106,9 @@ public abstract class InstantAppResolverService extends Service {
@Override
public void getInstantAppIntentFilterList(
int digestPrefix[], String token, String hostName, IRemoteCallback callback) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "[" + token + "] Phase2 called; posting");
+ }
final SomeArgs args = SomeArgs.obtain();
args.arg1 = callback;
args.arg2 = digestPrefix;
@@ -140,7 +146,7 @@ public abstract class InstantAppResolverService extends Service {
void _onGetInstantAppResolveInfo(int[] digestPrefix, String token,
InstantAppResolutionCallback callback) {
if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Instant resolver; getInstantAppResolveInfo;"
+ Slog.d(TAG, "[" + token + "] Phase1 request;"
+ " prefix: " + Arrays.toString(digestPrefix));
}
onGetInstantAppResolveInfo(digestPrefix, token, callback);
@@ -149,7 +155,7 @@ public abstract class InstantAppResolverService extends Service {
void _onGetInstantAppIntentFilter(int digestPrefix[], String token, String hostName,
InstantAppResolutionCallback callback) {
if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Instant resolver; getInstantAppIntentFilter;"
+ Slog.d(TAG, "[" + token + "] Phase2 request;"
+ " prefix: " + Arrays.toString(digestPrefix));
}
onGetInstantAppIntentFilter(digestPrefix, token, callback);
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 21d78ee3a07a..9d08004c579a 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.util.Slog;
import android.util.TimedRemoteCaller;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.TransferPipe;
import java.io.FileDescriptor;
@@ -53,7 +54,9 @@ final class EphemeralResolverConnection implements DeathRecipient {
private static final String TAG = "PackageManager";
// This is running in a critical section and the timeout must be sufficiently low
private static final long BIND_SERVICE_TIMEOUT_MS =
- ("eng".equals(Build.TYPE)) ? 300 : 200;
+ ("eng".equals(Build.TYPE)) ? 500 : 300;
+ private static final long CALL_SERVICE_TIMEOUT_MS =
+ ("eng".equals(Build.TYPE)) ? 200 : 100;
private static final boolean DEBUG_EPHEMERAL = Build.IS_DEBUGGABLE;
private final Object mLock = new Object();
@@ -64,7 +67,9 @@ final class EphemeralResolverConnection implements DeathRecipient {
/** Intent used to bind to the service */
private final Intent mIntent;
- private volatile boolean mBindRequested;
+ @GuardedBy("mLock")
+ private volatile boolean mIsBinding;
+ @GuardedBy("mLock")
private IInstantAppResolver mRemoteInstance;
public EphemeralResolverConnection(
@@ -76,11 +81,18 @@ final class EphemeralResolverConnection implements DeathRecipient {
public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(int hashPrefix[],
String token) {
throwIfCalledOnMainThread();
+ IInstantAppResolver target = null;
try {
- return mGetEphemeralResolveInfoCaller.getEphemeralResolveInfoList(
- getRemoteInstanceLazy(), hashPrefix, token);
- } catch (RemoteException re) {
- } catch (TimeoutException te) {
+ target = getRemoteInstanceLazy(token);
+ return mGetEphemeralResolveInfoCaller
+ .getEphemeralResolveInfoList(target, hashPrefix, token);
+ } catch (RemoteException e) {
+ } catch (InterruptedException | TimeoutException e) {
+ if (target == null) {
+ Slog.w(TAG, "[" + token + "] Timeout! Phase1 binding to instant app resolver");
+ } else {
+ Slog.w(TAG, "[" + token + "] Timeout! Phase1 resolving instant app");
+ }
} finally {
synchronized (mLock) {
mLock.notifyAll();
@@ -107,70 +119,73 @@ final class EphemeralResolverConnection implements DeathRecipient {
}
};
try {
- getRemoteInstanceLazy()
+ getRemoteInstanceLazy(token)
.getInstantAppIntentFilterList(hashPrefix, token, hostName, remoteCallback);
- } catch (RemoteException re) {
- } catch (TimeoutException te) {
+ } catch (RemoteException e) {
+ } catch (InterruptedException | TimeoutException e) {
+ Slog.w(TAG, "[" + token + "] Timeout! Phase2 binding to instant app resolver");
}
}
- public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
- synchronized (mLock) {
- pw.append(prefix).append("bound=")
- .append((mRemoteInstance != null) ? "true" : "false").println();
-
- pw.flush();
- try {
- TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
- new String[] { prefix });
- } catch (IOException | TimeoutException | RemoteException e) {
- pw.println("Failed to dump remote instance: " + e);
- }
- }
- }
-
- private IInstantAppResolver getRemoteInstanceLazy() throws TimeoutException {
+ private IInstantAppResolver getRemoteInstanceLazy(String token)
+ throws TimeoutException, InterruptedException {
synchronized (mLock) {
if (mRemoteInstance != null) {
return mRemoteInstance;
}
- bindLocked();
+ bindLocked(token);
return mRemoteInstance;
}
}
- private void bindLocked() throws TimeoutException {
- if (mRemoteInstance != null) {
- return;
- }
-
- if (!mBindRequested) {
- mBindRequested = true;
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Binding to resolver service");
- }
- mContext.bindServiceAsUser(mIntent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.SYSTEM);
- }
-
+ private void waitForBind(String token) throws TimeoutException, InterruptedException {
final long startMillis = SystemClock.uptimeMillis();
- while (true) {
+ while (mIsBinding) {
if (mRemoteInstance != null) {
break;
}
final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
final long remainingMillis = BIND_SERVICE_TIMEOUT_MS - elapsedMillis;
if (remainingMillis <= 0) {
- throw new TimeoutException("Didn't bind to resolver in time.");
- }
- try {
- mLock.wait(remainingMillis);
- } catch (InterruptedException ie) {
- /* ignore */
+ throw new TimeoutException("[" + token + "] Didn't bind to resolver in time!");
}
+ mLock.wait(remainingMillis);
}
+ }
- mLock.notifyAll();
+ private void bindLocked(String token) throws TimeoutException, InterruptedException {
+ if (DEBUG_EPHEMERAL && mIsBinding && mRemoteInstance == null) {
+ Slog.i(TAG, "[" + token + "] Previous bind timed out; waiting for connection");
+ }
+ try {
+ waitForBind(token);
+ } catch (TimeoutException e) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.i(TAG, "[" + token + "] Previous connection never established; rebinding");
+ }
+ mContext.unbindService(mServiceConnection);
+ }
+ if (mRemoteInstance != null) {
+ return;
+ }
+ mIsBinding = true;
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "[" + token + "] Binding to instant app resolver");
+ }
+ boolean wasBound = false;
+ try {
+ final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+ wasBound = mContext
+ .bindServiceAsUser(mIntent, mServiceConnection, flags, UserHandle.SYSTEM);
+ if (wasBound) {
+ waitForBind(token);
+ } else {
+ Slog.w(TAG, "[" + token + "] Failed to bind to: " + mIntent);
+ }
+ } finally {
+ mIsBinding = wasBound && mRemoteInstance == null;
+ mLock.notifyAll();
+ }
}
private void throwIfCalledOnMainThread() {
@@ -182,13 +197,18 @@ final class EphemeralResolverConnection implements DeathRecipient {
@Override
public void binderDied() {
if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Binder died");
+ Slog.d(TAG, "Binder to instant app resolver died");
}
+ synchronized (mLock) {
+ handleBinderDiedLocked();
+ }
+ }
+
+ private void handleBinderDiedLocked() {
if (mRemoteInstance != null) {
mRemoteInstance.asBinder().unlinkToDeath(this, 0 /*flags*/);
}
mRemoteInstance = null;
- mBindRequested = false;
}
/**
@@ -203,13 +223,15 @@ final class EphemeralResolverConnection implements DeathRecipient {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Service connected");
+ Slog.d(TAG, "Connected to instant app resolver");
}
synchronized (mLock) {
+ mRemoteInstance = IInstantAppResolver.Stub.asInterface(service);
+ mIsBinding = false;
try {
service.linkToDeath(EphemeralResolverConnection.this, 0 /*flags*/);
- mRemoteInstance = IInstantAppResolver.Stub.asInterface(service);
} catch (RemoteException e) {
+ handleBinderDiedLocked();
}
mLock.notifyAll();
}
@@ -218,10 +240,10 @@ final class EphemeralResolverConnection implements DeathRecipient {
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Service disconnected");
+ Slog.d(TAG, "Disconnected from instant app resolver");
}
synchronized (mLock) {
- mRemoteInstance = null;
+ handleBinderDiedLocked();
}
}
}
@@ -231,7 +253,7 @@ final class EphemeralResolverConnection implements DeathRecipient {
private final IRemoteCallback mCallback;
public GetEphemeralResolveInfoCaller() {
- super(BIND_SERVICE_TIMEOUT_MS);
+ super(CALL_SERVICE_TIMEOUT_MS);
mCallback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 6f593b08e258..b56db047fd30 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -74,11 +74,11 @@ public abstract class InstantAppResolver {
public static AuxiliaryResolveInfo doInstantAppResolutionPhaseOne(Context context,
EphemeralResolverConnection connection, InstantAppRequest requestObj) {
- if (DEBUG_EPHEMERAL) {
- Log.d(TAG, "Resolving phase 1");
- }
final long startTime = System.currentTimeMillis();
final String token = UUID.randomUUID().toString();
+ if (DEBUG_EPHEMERAL) {
+ Log.d(TAG, "[" + token + "] Resolving phase 1");
+ }
final Intent intent = requestObj.origIntent;
final InstantAppDigest digest =
new InstantAppDigest(intent.getData().getHost(), 5 /*maxDigests*/);
@@ -89,7 +89,7 @@ public abstract class InstantAppResolver {
if (instantAppResolveInfoList == null || instantAppResolveInfoList.size() == 0) {
// No hash prefix match; there are no instant apps for this domain.
if (DEBUG_EPHEMERAL) {
- Log.d(TAG, "No results returned");
+ Log.d(TAG, "[" + token + "] No results returned");
}
return null;
}
@@ -98,21 +98,24 @@ public abstract class InstantAppResolver {
intent.getPackage(), digest, token);
logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token,
RESOLUTION_SUCCESS);
+ if (DEBUG_EPHEMERAL && resolveInfo == null) {
+ Log.d(TAG, "[" + token + "] No results matched");
+ }
return resolveInfo;
}
public static void doInstantAppResolutionPhaseTwo(Context context,
EphemeralResolverConnection connection, InstantAppRequest requestObj,
ActivityInfo instantAppInstaller, Handler callbackHandler) {
+ final long startTime = System.currentTimeMillis();
+ final String token = requestObj.responseObj.token;
if (DEBUG_EPHEMERAL) {
- Log.d(TAG, "Resolving phase 2");
+ Log.d(TAG, "[" + token + "] Resolving phase 2");
}
- final long startTime = System.currentTimeMillis();
final Intent intent = requestObj.origIntent;
final String hostName = intent.getData().getHost();
final InstantAppDigest digest = new InstantAppDigest(hostName, 5 /*maxDigests*/);
final int[] shaPrefix = digest.getDigestPrefix();
- final String token = requestObj.responseObj.token;
final PhaseTwoCallback callback = new PhaseTwoCallback() {
@Override
@@ -285,12 +288,16 @@ public abstract class InstantAppResolver {
if (!matchedResolveInfoList.isEmpty()) {
if (DEBUG_EPHEMERAL) {
final AuxiliaryResolveInfo info = matchedResolveInfoList.get(0);
- Log.d(TAG, "Found match;"
+ Log.d(TAG, "[" + token + "] Found match;"
+ " package: " + info.packageName
+ ", split: " + info.splitName
+ ", versionCode: " + info.versionCode);
}
return matchedResolveInfoList.get(0);
+ } else if (DEBUG_EPHEMERAL) {
+ Log.d(TAG, "[" + token + "] No matches found"
+ + " package: " + instantAppInfo.getPackageName()
+ + ", versionCode: " + instantAppInfo.getVersionCode());
}
}
}