|
160 | 160 | import java.util.concurrent.TimeUnit; |
161 | 161 | import java.util.concurrent.atomic.AtomicBoolean; |
162 | 162 | import java.util.concurrent.atomic.AtomicInteger; |
| 163 | +import java.util.function.BiConsumer; |
163 | 164 | import java.util.function.Consumer; |
164 | 165 |
|
165 | 166 | /** |
@@ -1920,20 +1921,26 @@ private boolean startUserInternal(@UserIdInt int userId, int displayId, |
1920 | 1921 | return false; |
1921 | 1922 | } |
1922 | 1923 |
|
1923 | | - mHandler.post(() -> startUserInternalOnHandler(userId, oldUserId, userStartMode, |
1924 | | - unlockListener, callingUid, callingPid)); |
| 1924 | + final Runnable continueStartUserInternal = () -> continueStartUserInternal(userInfo, |
| 1925 | + oldUserId, userStartMode, unlockListener, callingUid, callingPid); |
| 1926 | + if (foreground) { |
| 1927 | + mHandler.post(() -> dispatchOnBeforeUserSwitching(userId, () -> |
| 1928 | + mHandler.post(continueStartUserInternal))); |
| 1929 | + } else { |
| 1930 | + continueStartUserInternal.run(); |
| 1931 | + } |
1925 | 1932 | } finally { |
1926 | 1933 | Binder.restoreCallingIdentity(ident); |
1927 | 1934 | } |
1928 | 1935 |
|
1929 | 1936 | return true; |
1930 | 1937 | } |
1931 | 1938 |
|
1932 | | - private void startUserInternalOnHandler(int userId, int oldUserId, int userStartMode, |
| 1939 | + private void continueStartUserInternal(UserInfo userInfo, int oldUserId, int userStartMode, |
1933 | 1940 | IProgressListener unlockListener, int callingUid, int callingPid) { |
1934 | 1941 | final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); |
1935 | 1942 | final boolean foreground = userStartMode == USER_START_MODE_FOREGROUND; |
1936 | | - final UserInfo userInfo = getUserInfo(userId); |
| 1943 | + final int userId = userInfo.id; |
1937 | 1944 |
|
1938 | 1945 | boolean needStart = false; |
1939 | 1946 | boolean updateUmState = false; |
@@ -1995,7 +2002,6 @@ private void startUserInternalOnHandler(int userId, int oldUserId, int userStart |
1995 | 2002 | // it should be moved outside, but for now it's not as there are many calls to |
1996 | 2003 | // external components here afterwards |
1997 | 2004 | updateProfileRelatedCaches(); |
1998 | | - dispatchOnBeforeUserSwitching(userId); |
1999 | 2005 | mInjector.getWindowManager().setCurrentUser(userId); |
2000 | 2006 | mInjector.reportCurWakefulnessUsageEvent(); |
2001 | 2007 | // Once the internal notion of the active user has switched, we lock the device |
@@ -2296,25 +2302,42 @@ private void dispatchForegroundProfileChanged(@UserIdInt int userId) { |
2296 | 2302 | mUserSwitchObservers.finishBroadcast(); |
2297 | 2303 | } |
2298 | 2304 |
|
2299 | | - private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId) { |
| 2305 | + private void dispatchOnBeforeUserSwitching(@UserIdInt int newUserId, Runnable onComplete) { |
2300 | 2306 | final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); |
2301 | 2307 | t.traceBegin("dispatchOnBeforeUserSwitching-" + newUserId); |
2302 | | - final int observerCount = mUserSwitchObservers.beginBroadcast(); |
2303 | | - for (int i = 0; i < observerCount; i++) { |
2304 | | - final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); |
2305 | | - t.traceBegin("onBeforeUserSwitching-" + name); |
| 2308 | + final AtomicBoolean isFirst = new AtomicBoolean(true); |
| 2309 | + startTimeoutForOnBeforeUserSwitching(isFirst, onComplete); |
| 2310 | + informUserSwitchObservers((observer, callback) -> { |
2306 | 2311 | try { |
2307 | | - mUserSwitchObservers.getBroadcastItem(i).onBeforeUserSwitching(newUserId); |
| 2312 | + observer.onBeforeUserSwitching(newUserId, callback); |
2308 | 2313 | } catch (RemoteException e) { |
2309 | | - // Ignore |
2310 | | - } finally { |
2311 | | - t.traceEnd(); |
| 2314 | + // ignore |
2312 | 2315 | } |
2313 | | - } |
2314 | | - mUserSwitchObservers.finishBroadcast(); |
| 2316 | + }, () -> { |
| 2317 | + if (isFirst.getAndSet(false)) { |
| 2318 | + onComplete.run(); |
| 2319 | + } |
| 2320 | + }, "onBeforeUserSwitching"); |
2315 | 2321 | t.traceEnd(); |
2316 | 2322 | } |
2317 | 2323 |
|
| 2324 | + private void startTimeoutForOnBeforeUserSwitching(AtomicBoolean isFirst, |
| 2325 | + Runnable onComplete) { |
| 2326 | + final long timeout = getUserSwitchTimeoutMs(); |
| 2327 | + mHandler.postDelayed(() -> { |
| 2328 | + if (isFirst.getAndSet(false)) { |
| 2329 | + String unresponsiveObservers; |
| 2330 | + synchronized (mLock) { |
| 2331 | + unresponsiveObservers = String.join(", ", mCurWaitingUserSwitchCallbacks); |
| 2332 | + } |
| 2333 | + Slogf.e(TAG, "Timeout on dispatchOnBeforeUserSwitching. These UserSwitchObservers " |
| 2334 | + + "did not respond in " + timeout + "ms: " + unresponsiveObservers + "."); |
| 2335 | + onComplete.run(); |
| 2336 | + } |
| 2337 | + }, timeout); |
| 2338 | + } |
| 2339 | + |
| 2340 | + |
2318 | 2341 | /** Called on handler thread */ |
2319 | 2342 | @VisibleForTesting |
2320 | 2343 | void dispatchUserSwitchComplete(@UserIdInt int oldUserId, @UserIdInt int newUserId) { |
@@ -2527,70 +2550,76 @@ void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newU |
2527 | 2550 | t.traceBegin("dispatchUserSwitch-" + oldUserId + "-to-" + newUserId); |
2528 | 2551 |
|
2529 | 2552 | EventLog.writeEvent(EventLogTags.UC_DISPATCH_USER_SWITCH, oldUserId, newUserId); |
| 2553 | + uss.switching = true; |
| 2554 | + informUserSwitchObservers((observer, callback) -> { |
| 2555 | + try { |
| 2556 | + observer.onUserSwitching(newUserId, callback); |
| 2557 | + } catch (RemoteException e) { |
| 2558 | + // ignore |
| 2559 | + } |
| 2560 | + }, () -> { |
| 2561 | + synchronized (mLock) { |
| 2562 | + sendContinueUserSwitchLU(uss, oldUserId, newUserId); |
| 2563 | + } |
| 2564 | + }, "onUserSwitching"); |
| 2565 | + t.traceEnd(); |
| 2566 | + } |
2530 | 2567 |
|
| 2568 | + void informUserSwitchObservers(BiConsumer<IUserSwitchObserver, IRemoteCallback> consumer, |
| 2569 | + final Runnable onComplete, String trace) { |
2531 | 2570 | final int observerCount = mUserSwitchObservers.beginBroadcast(); |
2532 | | - if (observerCount > 0) { |
2533 | | - final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); |
| 2571 | + if (observerCount == 0) { |
| 2572 | + onComplete.run(); |
| 2573 | + mUserSwitchObservers.finishBroadcast(); |
| 2574 | + return; |
| 2575 | + } |
| 2576 | + final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>(); |
| 2577 | + synchronized (mLock) { |
| 2578 | + mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; |
| 2579 | + } |
| 2580 | + final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); |
| 2581 | + final long userSwitchTimeoutMs = getUserSwitchTimeoutMs(); |
| 2582 | + final long dispatchStartedTime = SystemClock.elapsedRealtime(); |
| 2583 | + for (int i = 0; i < observerCount; i++) { |
| 2584 | + final long dispatchStartedTimeForObserver = SystemClock.elapsedRealtime(); |
| 2585 | + // Prepend with unique prefix to guarantee that keys are unique |
| 2586 | + final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); |
2534 | 2587 | synchronized (mLock) { |
2535 | | - uss.switching = true; |
2536 | | - mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks; |
2537 | | - } |
2538 | | - final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount); |
2539 | | - final long userSwitchTimeoutMs = getUserSwitchTimeoutMs(); |
2540 | | - final long dispatchStartedTime = SystemClock.elapsedRealtime(); |
2541 | | - for (int i = 0; i < observerCount; i++) { |
2542 | | - final long dispatchStartedTimeForObserver = SystemClock.elapsedRealtime(); |
2543 | | - try { |
2544 | | - // Prepend with unique prefix to guarantee that keys are unique |
2545 | | - final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i); |
| 2588 | + curWaitingUserSwitchCallbacks.add(name); |
| 2589 | + } |
| 2590 | + final IRemoteCallback callback = new IRemoteCallback.Stub() { |
| 2591 | + @Override |
| 2592 | + public void sendResult(Bundle data) throws RemoteException { |
| 2593 | + asyncTraceEnd(trace + "-" + name, 0); |
2546 | 2594 | synchronized (mLock) { |
2547 | | - curWaitingUserSwitchCallbacks.add(name); |
2548 | | - } |
2549 | | - final IRemoteCallback callback = new IRemoteCallback.Stub() { |
2550 | | - @Override |
2551 | | - public void sendResult(Bundle data) throws RemoteException { |
2552 | | - asyncTraceEnd("onUserSwitching-" + name, newUserId); |
2553 | | - synchronized (mLock) { |
2554 | | - long delayForObserver = SystemClock.elapsedRealtime() |
2555 | | - - dispatchStartedTimeForObserver; |
2556 | | - if (delayForObserver > LONG_USER_SWITCH_OBSERVER_WARNING_TIME_MS) { |
2557 | | - Slogf.w(TAG, "User switch slowed down by observer " + name |
2558 | | - + ": result took " + delayForObserver |
2559 | | - + " ms to process."); |
2560 | | - } |
2561 | | - |
2562 | | - long totalDelay = SystemClock.elapsedRealtime() |
2563 | | - - dispatchStartedTime; |
2564 | | - if (totalDelay > userSwitchTimeoutMs) { |
2565 | | - Slogf.e(TAG, "User switch timeout: observer " + name |
2566 | | - + "'s result was received " + totalDelay |
2567 | | - + " ms after dispatchUserSwitch."); |
2568 | | - } |
2569 | | - |
2570 | | - curWaitingUserSwitchCallbacks.remove(name); |
2571 | | - // Continue switching if all callbacks have been notified and |
2572 | | - // user switching session is still valid |
2573 | | - if (waitingCallbacksCount.decrementAndGet() == 0 |
2574 | | - && (curWaitingUserSwitchCallbacks |
2575 | | - == mCurWaitingUserSwitchCallbacks)) { |
2576 | | - sendContinueUserSwitchLU(uss, oldUserId, newUserId); |
2577 | | - } |
2578 | | - } |
| 2595 | + long delayForObserver = SystemClock.elapsedRealtime() |
| 2596 | + - dispatchStartedTimeForObserver; |
| 2597 | + if (delayForObserver > LONG_USER_SWITCH_OBSERVER_WARNING_TIME_MS) { |
| 2598 | + Slogf.w(TAG, "User switch slowed down by observer " + name |
| 2599 | + + ": result took " + delayForObserver |
| 2600 | + + " ms to process. " + trace); |
2579 | 2601 | } |
2580 | | - }; |
2581 | | - asyncTraceBegin("onUserSwitching-" + name, newUserId); |
2582 | | - mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback); |
2583 | | - } catch (RemoteException e) { |
2584 | | - // Ignore |
| 2602 | + long totalDelay = SystemClock.elapsedRealtime() - dispatchStartedTime; |
| 2603 | + if (totalDelay > userSwitchTimeoutMs) { |
| 2604 | + Slogf.e(TAG, "User switch timeout: observer " + name |
| 2605 | + + "'s result was received " + totalDelay |
| 2606 | + + " ms after dispatchUserSwitch. " + trace); |
| 2607 | + } |
| 2608 | + curWaitingUserSwitchCallbacks.remove(name); |
| 2609 | + // Continue switching if all callbacks have been notified and |
| 2610 | + // user switching session is still valid |
| 2611 | + if (waitingCallbacksCount.decrementAndGet() == 0 |
| 2612 | + && (curWaitingUserSwitchCallbacks |
| 2613 | + == mCurWaitingUserSwitchCallbacks)) { |
| 2614 | + onComplete.run(); |
| 2615 | + } |
| 2616 | + } |
2585 | 2617 | } |
2586 | | - } |
2587 | | - } else { |
2588 | | - synchronized (mLock) { |
2589 | | - sendContinueUserSwitchLU(uss, oldUserId, newUserId); |
2590 | | - } |
| 2618 | + }; |
| 2619 | + asyncTraceBegin(trace + "-" + name, 0); |
| 2620 | + consumer.accept(mUserSwitchObservers.getBroadcastItem(i), callback); |
2591 | 2621 | } |
2592 | 2622 | mUserSwitchObservers.finishBroadcast(); |
2593 | | - t.traceEnd(); // end dispatchUserSwitch- |
2594 | 2623 | } |
2595 | 2624 |
|
2596 | 2625 | @GuardedBy("mLock") |
|
0 commit comments