Loading services/core/java/com/android/server/pm/EphemeralResolverConnection.java +75 −34 Original line number Diff line number Diff line Loading @@ -69,8 +69,12 @@ final class EphemeralResolverConnection implements DeathRecipient { /** Intent used to bind to the service */ private final Intent mIntent; private static final int STATE_IDLE = 0; // no bind operation is ongoing private static final int STATE_BINDING = 1; // someone is binding and waiting private static final int STATE_PENDING = 2; // a bind is pending, but the caller is not waiting @GuardedBy("mLock") private volatile boolean mIsBinding; private int mBindState = STATE_IDLE; @GuardedBy("mLock") private IInstantAppResolver mRemoteInstance; Loading Loading @@ -137,23 +141,17 @@ final class EphemeralResolverConnection implements DeathRecipient { private IInstantAppResolver getRemoteInstanceLazy(String token) throws ConnectionException, TimeoutException, InterruptedException { synchronized (mLock) { if (mRemoteInstance != null) { return mRemoteInstance; } long binderToken = Binder.clearCallingIdentity(); try { bindLocked(token); return bind(token); } finally { Binder.restoreCallingIdentity(binderToken); } return mRemoteInstance; } } private void waitForBindLocked(String token) throws TimeoutException, InterruptedException { final long startMillis = SystemClock.uptimeMillis(); while (mIsBinding) { while (mBindState != STATE_IDLE) { if (mRemoteInstance != null) { break; } Loading @@ -166,42 +164,83 @@ final class EphemeralResolverConnection implements DeathRecipient { } } private void bindLocked(String token) private IInstantAppResolver bind(String token) throws ConnectionException, TimeoutException, InterruptedException { if (DEBUG_EPHEMERAL && mIsBinding && mRemoteInstance == null) { boolean doUnbind = false; synchronized (mLock) { if (mRemoteInstance != null) { return mRemoteInstance; } if (mBindState == STATE_PENDING) { // there is a pending bind, let's see if we can use it. if (DEBUG_EPHEMERAL) { Slog.i(TAG, "[" + token + "] Previous bind timed out; waiting for connection"); } try { waitForBindLocked(token); if (mRemoteInstance != null) { return mRemoteInstance; } } catch (TimeoutException e) { // nope, we might have to try a rebind. doUnbind = true; } } if (mBindState == STATE_BINDING) { // someone was binding when we called bind(), or they raced ahead while we were // waiting in the PENDING case; wait for their result instead. Last chance! if (DEBUG_EPHEMERAL) { Slog.i(TAG, "[" + token + "] Another thread is binding; waiting for connection"); } waitForBindLocked(token); // if the other thread's bindService() returned false, we could still have null. if (mRemoteInstance != null) { return mRemoteInstance; } throw new ConnectionException(ConnectionException.FAILURE_BIND); } mBindState = STATE_BINDING; // our time to shine! :) } // only one thread can be here at a time (the one that set STATE_BINDING) boolean wasBound = false; IInstantAppResolver instance = null; try { if (doUnbind) { 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) { synchronized (mLock) { waitForBindLocked(token); instance = mRemoteInstance; return instance; } } else { Slog.w(TAG, "[" + token + "] Failed to bind to: " + mIntent); throw new ConnectionException(ConnectionException.FAILURE_BIND); } } finally { mIsBinding = wasBound && mRemoteInstance == null; synchronized (mLock) { if (wasBound && instance == null) { mBindState = STATE_PENDING; } else { mBindState = STATE_IDLE; } mLock.notifyAll(); } } } private void throwIfCalledOnMainThread() { if (Thread.currentThread() == mContext.getMainLooper().getThread()) { Loading Loading @@ -255,7 +294,9 @@ final class EphemeralResolverConnection implements DeathRecipient { } synchronized (mLock) { mRemoteInstance = IInstantAppResolver.Stub.asInterface(service); mIsBinding = false; if (mBindState == STATE_PENDING) { mBindState = STATE_IDLE; } try { service.linkToDeath(EphemeralResolverConnection.this, 0 /*flags*/); } catch (RemoteException e) { Loading Loading
services/core/java/com/android/server/pm/EphemeralResolverConnection.java +75 −34 Original line number Diff line number Diff line Loading @@ -69,8 +69,12 @@ final class EphemeralResolverConnection implements DeathRecipient { /** Intent used to bind to the service */ private final Intent mIntent; private static final int STATE_IDLE = 0; // no bind operation is ongoing private static final int STATE_BINDING = 1; // someone is binding and waiting private static final int STATE_PENDING = 2; // a bind is pending, but the caller is not waiting @GuardedBy("mLock") private volatile boolean mIsBinding; private int mBindState = STATE_IDLE; @GuardedBy("mLock") private IInstantAppResolver mRemoteInstance; Loading Loading @@ -137,23 +141,17 @@ final class EphemeralResolverConnection implements DeathRecipient { private IInstantAppResolver getRemoteInstanceLazy(String token) throws ConnectionException, TimeoutException, InterruptedException { synchronized (mLock) { if (mRemoteInstance != null) { return mRemoteInstance; } long binderToken = Binder.clearCallingIdentity(); try { bindLocked(token); return bind(token); } finally { Binder.restoreCallingIdentity(binderToken); } return mRemoteInstance; } } private void waitForBindLocked(String token) throws TimeoutException, InterruptedException { final long startMillis = SystemClock.uptimeMillis(); while (mIsBinding) { while (mBindState != STATE_IDLE) { if (mRemoteInstance != null) { break; } Loading @@ -166,42 +164,83 @@ final class EphemeralResolverConnection implements DeathRecipient { } } private void bindLocked(String token) private IInstantAppResolver bind(String token) throws ConnectionException, TimeoutException, InterruptedException { if (DEBUG_EPHEMERAL && mIsBinding && mRemoteInstance == null) { boolean doUnbind = false; synchronized (mLock) { if (mRemoteInstance != null) { return mRemoteInstance; } if (mBindState == STATE_PENDING) { // there is a pending bind, let's see if we can use it. if (DEBUG_EPHEMERAL) { Slog.i(TAG, "[" + token + "] Previous bind timed out; waiting for connection"); } try { waitForBindLocked(token); if (mRemoteInstance != null) { return mRemoteInstance; } } catch (TimeoutException e) { // nope, we might have to try a rebind. doUnbind = true; } } if (mBindState == STATE_BINDING) { // someone was binding when we called bind(), or they raced ahead while we were // waiting in the PENDING case; wait for their result instead. Last chance! if (DEBUG_EPHEMERAL) { Slog.i(TAG, "[" + token + "] Another thread is binding; waiting for connection"); } waitForBindLocked(token); // if the other thread's bindService() returned false, we could still have null. if (mRemoteInstance != null) { return mRemoteInstance; } throw new ConnectionException(ConnectionException.FAILURE_BIND); } mBindState = STATE_BINDING; // our time to shine! :) } // only one thread can be here at a time (the one that set STATE_BINDING) boolean wasBound = false; IInstantAppResolver instance = null; try { if (doUnbind) { 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) { synchronized (mLock) { waitForBindLocked(token); instance = mRemoteInstance; return instance; } } else { Slog.w(TAG, "[" + token + "] Failed to bind to: " + mIntent); throw new ConnectionException(ConnectionException.FAILURE_BIND); } } finally { mIsBinding = wasBound && mRemoteInstance == null; synchronized (mLock) { if (wasBound && instance == null) { mBindState = STATE_PENDING; } else { mBindState = STATE_IDLE; } mLock.notifyAll(); } } } private void throwIfCalledOnMainThread() { if (Thread.currentThread() == mContext.getMainLooper().getThread()) { Loading Loading @@ -255,7 +294,9 @@ final class EphemeralResolverConnection implements DeathRecipient { } synchronized (mLock) { mRemoteInstance = IInstantAppResolver.Stub.asInterface(service); mIsBinding = false; if (mBindState == STATE_PENDING) { mBindState = STATE_IDLE; } try { service.linkToDeath(EphemeralResolverConnection.this, 0 /*flags*/); } catch (RemoteException e) { Loading