diff options
23 files changed, 493 insertions, 408 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d67b98620f37..267b81823688 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -614,7 +614,7 @@ public final class ActivityThread extends ClientTransactionHandler { throw new IllegalStateException( "Received config update for non-existing activity"); } - activity.mMainThread.handleActivityConfigurationChanged(token, overrideConfig, + activity.mMainThread.handleActivityConfigurationChanged(this, overrideConfig, newDisplayId); }; } @@ -3475,13 +3475,9 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) { - final ActivityClientRecord r = mActivities.get(token); + public void handleStartActivity(ActivityClientRecord r, + PendingTransactionActions pendingActions) { final Activity activity = r.activity; - if (r.activity == null) { - // TODO(lifecycler): What do we do in this case? - return; - } if (!r.stopped) { throw new IllegalStateException("Can't start activity that is not stopped."); } @@ -3687,12 +3683,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleNewIntent(IBinder token, List<ReferrerIntent> intents) { - final ActivityClientRecord r = mActivities.get(token); - if (r == null) { - return; - } - + public void handleNewIntent(ActivityClientRecord r, List<ReferrerIntent> intents) { checkAndBlockForNetworkAccess(); deliverNewIntents(r, intents); } @@ -3881,13 +3872,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handlePictureInPictureRequested(IBinder token) { - final ActivityClientRecord r = mActivities.get(token); - if (r == null) { - Log.w(TAG, "Activity to request PIP to no longer exists"); - return; - } - + public void handlePictureInPictureRequested(ActivityClientRecord r) { final boolean receivedByApp = r.activity.onPictureInPictureRequested(); if (!receivedByApp) { // Previous recommendation was for apps to enter picture-in-picture in @@ -4417,22 +4402,21 @@ public final class ActivityThread extends ClientTransactionHandler { /** * Resume the activity. - * @param token Target activity token. + * @param r Target activity record. * @param finalStateRequest Flag indicating if this is part of final state resolution for a * transaction. * @param reason Reason for performing the action. * - * @return The {@link ActivityClientRecord} that was resumed, {@code null} otherwise. + * @return {@code true} that was resumed, {@code false} otherwise. */ @VisibleForTesting - public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, + public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest, String reason) { - final ActivityClientRecord r = mActivities.get(token); if (localLOGV) { Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); } - if (r == null || r.activity.mFinished) { - return null; + if (r.activity.mFinished) { + return false; } if (r.getLifecycleState() == ON_RESUME) { if (!finalStateRequest) { @@ -4446,7 +4430,7 @@ public final class ActivityThread extends ClientTransactionHandler { // handle two resume requests for the final state. For cases other than this // one, we don't expect it to happen. } - return null; + return false; } if (finalStateRequest) { r.hideForNow = false; @@ -4477,7 +4461,7 @@ public final class ActivityThread extends ClientTransactionHandler { + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } - return r; + return true; } static final void cleanUpPendingRemoveWindows(ActivityClientRecord r, boolean force) { @@ -4498,20 +4482,19 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, - String reason) { + public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest, + boolean isForward, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true; // TODO Push resumeArgs into the activity for consideration - final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); - if (r == null) { - // We didn't actually resume the activity, so skipping any follow-up actions. + // skip below steps for double-resume and r.mFinish = true case. + if (!performResumeActivity(r, finalStateRequest, reason)) { return; } - if (mActivitiesToBeDestroyed.containsKey(token)) { + if (mActivitiesToBeDestroyed.containsKey(r.token)) { // Although the activity is resumed, it is going to be destroyed. So the following // UI operations are unnecessary and also prevents exception because its token may // be gone that window manager cannot recognize it. All necessary cleanup actions @@ -4629,13 +4612,8 @@ public final class ActivityThread extends ClientTransactionHandler { @Override - public void handleTopResumedActivityChanged(IBinder token, boolean onTop, String reason) { - ActivityClientRecord r = mActivities.get(token); - if (r == null || r.activity == null) { - Slog.w(TAG, "Not found target activity to report position change for token: " + token); - return; - } - + public void handleTopResumedActivityChanged(ActivityClientRecord r, boolean onTop, + String reason) { if (DEBUG_ORDER) { Slog.d(TAG, "Received position change to top: " + onTop + " for activity: " + r); } @@ -4668,23 +4646,20 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, + public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason) { - ActivityClientRecord r = mActivities.get(token); - if (r != null) { - if (userLeaving) { - performUserLeavingActivity(r); - } + if (userLeaving) { + performUserLeavingActivity(r); + } - r.activity.mConfigChangeFlags |= configChanges; - performPauseActivity(r, finished, reason, pendingActions); + r.activity.mConfigChangeFlags |= configChanges; + performPauseActivity(r, finished, reason, pendingActions); - // Make sure any pending writes are now committed. - if (r.isPreHoneycomb()) { - QueuedWork.waitToFinish(); - } - mSomeActivitiesChanged = true; + // Make sure any pending writes are now committed. + if (r.isPreHoneycomb()) { + QueuedWork.waitToFinish(); } + mSomeActivitiesChanged = true; } final void performUserLeavingActivity(ActivityClientRecord r) { @@ -4781,8 +4756,11 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_PAUSE); } + // TODO(b/127877792): Make LocalActivityManager call performStopActivityInner. We cannot do this + // since it's a high usage hidden API. /** Called from {@link LocalActivityManager}. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 127877792, + publicAlternatives = "{@code N/A}") final void performStopActivity(IBinder token, boolean saveState, String reason) { ActivityClientRecord r = mActivities.get(token); performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */, @@ -4823,39 +4801,37 @@ public final class ActivityThread extends ClientTransactionHandler { private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean saveState, boolean finalStateRequest, String reason) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); - if (r != null) { - if (r.stopped) { - if (r.activity.mFinished) { - // If we are finishing, we won't call onResume() in certain - // cases. So here we likewise don't want to call onStop() - // if the activity isn't resumed. - return; - } - if (!finalStateRequest) { - final RuntimeException e = new RuntimeException( - "Performing stop of activity that is already stopped: " - + r.intent.getComponent().toShortString()); - Slog.e(TAG, e.getMessage(), e); - Slog.e(TAG, r.getStateString()); - } + if (r.stopped) { + if (r.activity.mFinished) { + // If we are finishing, we won't call onResume() in certain + // cases. So here we likewise don't want to call onStop() + // if the activity isn't resumed. + return; + } + if (!finalStateRequest) { + final RuntimeException e = new RuntimeException( + "Performing stop of activity that is already stopped: " + + r.intent.getComponent().toShortString()); + Slog.e(TAG, e.getMessage(), e); + Slog.e(TAG, r.getStateString()); } + } - // One must first be paused before stopped... - performPauseActivityIfNeeded(r, reason); + // One must first be paused before stopped... + performPauseActivityIfNeeded(r, reason); - if (info != null) { - try { - // First create a thumbnail for the activity... - // For now, don't create the thumbnail here; we are - // doing that by doing a screen snapshot. - info.setDescription(r.activity.onCreateDescription()); - } catch (Exception e) { - if (!mInstrumentation.onException(r.activity, e)) { - throw new RuntimeException( - "Unable to save state of activity " - + r.intent.getComponent().toShortString() - + ": " + e.toString(), e); - } + if (info != null) { + try { + // First create a thumbnail for the activity... + // For now, don't create the thumbnail here; we are + // doing that by doing a screen snapshot. + info.setDescription(r.activity.onCreateDescription()); + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to save state of activity " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); } } @@ -4927,9 +4903,8 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleStopActivity(IBinder token, int configChanges, + public void handleStopActivity(ActivityClientRecord r, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) { - final ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; final StopInfo stopInfo = new StopInfo(); @@ -4965,8 +4940,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void performRestartActivity(IBinder token, boolean start) { - ActivityClientRecord r = mActivities.get(token); + public void performRestartActivity(ActivityClientRecord r, boolean start) { if (r.stopped) { r.activity.performRestart(start, "performRestartActivity"); if (start) { @@ -5053,107 +5027,101 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleSendResult(IBinder token, List<ResultInfo> results, String reason) { - ActivityClientRecord r = mActivities.get(token); + public void handleSendResult(ActivityClientRecord r, List<ResultInfo> results, String reason) { if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r); - if (r != null) { - final boolean resumed = !r.paused; - if (!r.activity.mFinished && r.activity.mDecor != null - && r.hideForNow && resumed) { - // We had hidden the activity because it started another - // one... we have gotten a result back and we are not - // paused, so make sure our window is visible. - updateVisibility(r, true); - } - if (resumed) { - try { - // Now we are idle. - r.activity.mCalled = false; - mInstrumentation.callActivityOnPause(r.activity); - if (!r.activity.mCalled) { - throw new SuperNotCalledException( - "Activity " + r.intent.getComponent().toShortString() - + " did not call through to super.onPause()"); - } - } catch (SuperNotCalledException e) { - throw e; - } catch (Exception e) { - if (!mInstrumentation.onException(r.activity, e)) { - throw new RuntimeException( - "Unable to pause activity " - + r.intent.getComponent().toShortString() - + ": " + e.toString(), e); - } + final boolean resumed = !r.paused; + if (!r.activity.mFinished && r.activity.mDecor != null + && r.hideForNow && resumed) { + // We had hidden the activity because it started another + // one... we have gotten a result back and we are not + // paused, so make sure our window is visible. + updateVisibility(r, true); + } + if (resumed) { + try { + // Now we are idle. + r.activity.mCalled = false; + mInstrumentation.callActivityOnPause(r.activity); + if (!r.activity.mCalled) { + throw new SuperNotCalledException( + "Activity " + r.intent.getComponent().toShortString() + + " did not call through to super.onPause()"); + } + } catch (SuperNotCalledException e) { + throw e; + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to pause activity " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); } - } - checkAndBlockForNetworkAccess(); - deliverResults(r, results, reason); - if (resumed) { - r.activity.performResume(false, reason); } } + checkAndBlockForNetworkAccess(); + deliverResults(r, results, reason); + if (resumed) { + r.activity.performResume(false, reason); + } } /** Core implementation of activity destroy call. */ - ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, + ActivityClientRecord performDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { - ActivityClientRecord r = mActivities.get(token); Class<? extends Activity> activityClass = null; if (localLOGV) Slog.v(TAG, "Performing finish of " + r); - if (r != null) { - activityClass = r.activity.getClass(); - r.activity.mConfigChangeFlags |= configChanges; - if (finishing) { - r.activity.mFinished = true; - } + activityClass = r.activity.getClass(); + r.activity.mConfigChangeFlags |= configChanges; + if (finishing) { + r.activity.mFinished = true; + } - performPauseActivityIfNeeded(r, "destroy"); + performPauseActivityIfNeeded(r, "destroy"); - if (!r.stopped) { - callActivityOnStop(r, false /* saveState */, "destroy"); - } - if (getNonConfigInstance) { - try { - r.lastNonConfigurationInstances - = r.activity.retainNonConfigurationInstances(); - } catch (Exception e) { - if (!mInstrumentation.onException(r.activity, e)) { - throw new RuntimeException( - "Unable to retain activity " - + r.intent.getComponent().toShortString() - + ": " + e.toString(), e); - } - } - } + if (!r.stopped) { + callActivityOnStop(r, false /* saveState */, "destroy"); + } + if (getNonConfigInstance) { try { - r.activity.mCalled = false; - mInstrumentation.callActivityOnDestroy(r.activity); - if (!r.activity.mCalled) { - throw new SuperNotCalledException( - "Activity " + safeToComponentShortString(r.intent) + - " did not call through to super.onDestroy()"); - } - if (r.window != null) { - r.window.closeAllPanels(); - } - } catch (SuperNotCalledException e) { - throw e; + r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( - "Unable to destroy activity " + safeToComponentShortString(r.intent) + "Unable to retain activity " + + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } r.setState(ON_DESTROY); mLastReportedWindowingMode.remove(r.activity.getActivityToken()); } + try { + r.activity.mCalled = false; + mInstrumentation.callActivityOnDestroy(r.activity); + if (!r.activity.mCalled) { + throw new SuperNotCalledException( + "Activity " + safeToComponentShortString(r.intent) + + " did not call through to super.onDestroy()"); + } + if (r.window != null) { + r.window.closeAllPanels(); + } + } catch (SuperNotCalledException e) { + throw e; + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to destroy activity " + safeToComponentShortString(r.intent) + + ": " + e.toString(), e); + } + } + r.setState(ON_DESTROY); schedulePurgeIdler(); // updatePendingActivityConfiguration() reads from mActivities to update // ActivityClientRecord which runs in a different thread. Protect modifications to // mActivities to avoid race. synchronized (mResourcesManager) { - mActivities.remove(token); + mActivities.remove(r.token); } StrictMode.decrementExpectedActivityCount(activityClass); return r; @@ -5170,70 +5138,67 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, + public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { - ActivityClientRecord r = performDestroyActivity(token, finishing, - configChanges, getNonConfigInstance, reason); - if (r != null) { - cleanUpPendingRemoveWindows(r, finishing); - WindowManager wm = r.activity.getWindowManager(); - View v = r.activity.mDecor; - if (v != null) { - if (r.activity.mVisibleFromServer) { - mNumVisibleActivities--; - } - IBinder wtoken = v.getWindowToken(); - if (r.activity.mWindowAdded) { - if (r.mPreserveWindow) { - // Hold off on removing this until the new activity's - // window is being added. - r.mPendingRemoveWindow = r.window; - r.mPendingRemoveWindowManager = wm; - // We can only keep the part of the view hierarchy that we control, - // everything else must be removed, because it might not be able to - // behave properly when activity is relaunching. - r.window.clearContentView(); - } else { - wm.removeViewImmediate(v); - } - } - if (wtoken != null && r.mPendingRemoveWindow == null) { - WindowManagerGlobal.getInstance().closeAll(wtoken, - r.activity.getClass().getName(), "Activity"); - } else if (r.mPendingRemoveWindow != null) { - // We're preserving only one window, others should be closed so app views - // will be detached before the final tear down. It should be done now because - // some components (e.g. WebView) rely on detach callbacks to perform receiver - // unregister and other cleanup. - WindowManagerGlobal.getInstance().closeAllExceptView(token, v, - r.activity.getClass().getName(), "Activity"); + r = performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason); + cleanUpPendingRemoveWindows(r, finishing); + WindowManager wm = r.activity.getWindowManager(); + View v = r.activity.mDecor; + if (v != null) { + if (r.activity.mVisibleFromServer) { + mNumVisibleActivities--; + } + IBinder wtoken = v.getWindowToken(); + if (r.activity.mWindowAdded) { + if (r.mPreserveWindow) { + // Hold off on removing this until the new activity's + // window is being added. + r.mPendingRemoveWindow = r.window; + r.mPendingRemoveWindowManager = wm; + // We can only keep the part of the view hierarchy that we control, + // everything else must be removed, because it might not be able to + // behave properly when activity is relaunching. + r.window.clearContentView(); + } else { + wm.removeViewImmediate(v); } - r.activity.mDecor = null; - } - if (r.mPendingRemoveWindow == null) { - // If we are delaying the removal of the activity window, then - // we can't clean up all windows here. Note that we can't do - // so later either, which means any windows that aren't closed - // by the app will leak. Well we try to warning them a lot - // about leaking windows, because that is a bug, so if they are - // using this recreate facility then they get to live with leaks. - WindowManagerGlobal.getInstance().closeAll(token, - r.activity.getClass().getName(), "Activity"); } - - // Mocked out contexts won't be participating in the normal - // process lifecycle, but if we're running with a proper - // ApplicationContext we need to have it tear down things - // cleanly. - Context c = r.activity.getBaseContext(); - if (c instanceof ContextImpl) { - ((ContextImpl) c).scheduleFinalCleanup( + if (wtoken != null && r.mPendingRemoveWindow == null) { + WindowManagerGlobal.getInstance().closeAll(wtoken, + r.activity.getClass().getName(), "Activity"); + } else if (r.mPendingRemoveWindow != null) { + // We're preserving only one window, others should be closed so app views + // will be detached before the final tear down. It should be done now because + // some components (e.g. WebView) rely on detach callbacks to perform receiver + // unregister and other cleanup. + WindowManagerGlobal.getInstance().closeAllExceptView(r.token, v, r.activity.getClass().getName(), "Activity"); } + r.activity.mDecor = null; + } + if (r.mPendingRemoveWindow == null) { + // If we are delaying the removal of the activity window, then + // we can't clean up all windows here. Note that we can't do + // so later either, which means any windows that aren't closed + // by the app will leak. Well we try to warning them a lot + // about leaking windows, because that is a bug, so if they are + // using this recreate facility then they get to live with leaks. + WindowManagerGlobal.getInstance().closeAll(r.token, + r.activity.getClass().getName(), "Activity"); + } + + // Mocked out contexts won't be participating in the normal + // process lifecycle, but if we're running with a proper + // ApplicationContext we need to have it tear down things + // cleanly. + Context c = r.activity.getBaseContext(); + if (c instanceof ContextImpl) { + ((ContextImpl) c).scheduleFinalCleanup( + r.activity.getClass().getName(), "Activity"); } if (finishing) { try { - ActivityTaskManager.getService().activityDestroyed(token); + ActivityTaskManager.getService().activityDestroyed(r.token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -5456,7 +5421,7 @@ public final class ActivityThread extends ClientTransactionHandler { callActivityOnStop(r, true /* saveState */, reason); } - handleDestroyActivity(r.token, false, configChanges, true, reason); + handleDestroyActivity(r, false, configChanges, true, reason); r.activity = null; r.window = null; @@ -5484,12 +5449,10 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) { + public void reportRelaunch(ActivityClientRecord r, PendingTransactionActions pendingActions) { try { - ActivityTaskManager.getService().activityRelaunched(token); - final ActivityClientRecord r = mActivities.get(token); - if (pendingActions.shouldReportRelaunchToWindowManager() && r != null - && r.window != null) { + ActivityTaskManager.getService().activityRelaunched(r.token); + if (pendingActions.shouldReportRelaunchToWindowManager() && r.window != null) { r.window.reportActivityRelaunched(); } } catch (RemoteException e) { @@ -5648,13 +5611,7 @@ public final class ActivityThread extends ClientTransactionHandler { */ private Configuration performActivityConfigurationChanged(Activity activity, Configuration newConfig, Configuration amOverrideConfig, int displayId) { - if (activity == null) { - throw new IllegalArgumentException("No activity provided."); - } final IBinder activityToken = activity.getActivityToken(); - if (activityToken == null) { - throw new IllegalArgumentException("Activity token not set. Is the activity attached?"); - } final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId); boolean shouldReportChange = false; @@ -5954,20 +5911,8 @@ public final class ActivityThread extends ClientTransactionHandler { * processing any configurations older than {@code overrideConfig}. */ @Override - public void updatePendingActivityConfiguration(IBinder activityToken, + public void updatePendingActivityConfiguration(ActivityClientRecord r, Configuration overrideConfig) { - final ActivityClientRecord r; - synchronized (mResourcesManager) { - r = mActivities.get(activityToken); - } - - if (r == null) { - if (DEBUG_CONFIGURATION) { - Slog.w(TAG, "Not found target activity to update its pending config."); - } - return; - } - synchronized (r) { if (r.mPendingOverrideConfig != null && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) { @@ -5987,21 +5932,14 @@ public final class ActivityThread extends ClientTransactionHandler { * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with * a newer config than {@code overrideConfig}. * - * @param activityToken Target activity token. + * @param r Target activity record. * @param overrideConfig Activity override config. * @param displayId Id of the display where activity was moved to, -1 if there was no move and * value didn't change. */ @Override - public void handleActivityConfigurationChanged(IBinder activityToken, + public void handleActivityConfigurationChanged(ActivityClientRecord r, @NonNull Configuration overrideConfig, int displayId) { - ActivityClientRecord r = mActivities.get(activityToken); - // Check input params. - if (r == null || r.activity == null) { - if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r); - return; - } - synchronized (r) { if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) { if (DEBUG_CONFIGURATION) { diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 2df756e80fde..ac50676ff46b 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -15,6 +15,8 @@ */ package android.app; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.ClientTransactionItem; import android.app.servertransaction.PendingTransactionActions; @@ -89,37 +91,38 @@ public abstract class ClientTransactionHandler { public abstract Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed(); /** Destroy the activity. */ - public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, - boolean getNonConfigInstance, String reason); + public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing, + int configChanges, boolean getNonConfigInstance, String reason); /** Pause the activity. */ - public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, - int configChanges, PendingTransactionActions pendingActions, String reason); + public abstract void handlePauseActivity(@NonNull ActivityClientRecord r, boolean finished, + boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, + String reason); /** * Resume the activity. - * @param token Target activity token. + * @param r Target activity record. * @param finalStateRequest Flag indicating if this call is handling final lifecycle state * request for a transaction. * @param isForward Flag indicating if next transition is forward. * @param reason Reason for performing this operation. */ - public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest, - boolean isForward, String reason); + public abstract void handleResumeActivity(@NonNull ActivityClientRecord r, + boolean finalStateRequest, boolean isForward, String reason); /** * Notify the activity about top resumed state change. - * @param token Target activity token. + * @param r Target activity record. * @param isTopResumedActivity Current state of the activity, {@code true} if it's the * topmost resumed activity in the system, {@code false} otherwise. * @param reason Reason for performing this operation. */ - public abstract void handleTopResumedActivityChanged(IBinder token, + public abstract void handleTopResumedActivityChanged(@NonNull ActivityClientRecord r, boolean isTopResumedActivity, String reason); /** * Stop the activity. - * @param token Target activity token. + * @param r Target activity record. * @param configChanges Activity configuration changes. * @param pendingActions Pending actions to be used on this or later stages of activity * transaction. @@ -127,38 +130,40 @@ public abstract class ClientTransactionHandler { * request for a transaction. * @param reason Reason for performing this operation. */ - public abstract void handleStopActivity(IBinder token, int configChanges, + public abstract void handleStopActivity(@NonNull ActivityClientRecord r, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason); /** Report that activity was stopped to server. */ public abstract void reportStop(PendingTransactionActions pendingActions); /** Restart the activity after it was stopped. */ - public abstract void performRestartActivity(IBinder token, boolean start); + public abstract void performRestartActivity(@NonNull ActivityClientRecord r, boolean start); /** Set pending activity configuration in case it will be updated by other transaction item. */ - public abstract void updatePendingActivityConfiguration(IBinder activityToken, + public abstract void updatePendingActivityConfiguration(@NonNull ActivityClientRecord r, Configuration overrideConfig); /** Deliver activity (override) configuration change. */ - public abstract void handleActivityConfigurationChanged(IBinder activityToken, + public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r, Configuration overrideConfig, int displayId); /** Deliver result from another activity. */ - public abstract void handleSendResult(IBinder token, List<ResultInfo> results, String reason); + public abstract void handleSendResult( + @NonNull ActivityClientRecord r, List<ResultInfo> results, String reason); /** Deliver new intent. */ - public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents); + public abstract void handleNewIntent( + @NonNull ActivityClientRecord r, List<ReferrerIntent> intents); /** Request that an activity enter picture-in-picture. */ - public abstract void handlePictureInPictureRequested(IBinder token); + public abstract void handlePictureInPictureRequested(@NonNull ActivityClientRecord r); /** Perform activity launch. */ - public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r, + public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent); /** Perform activity start. */ - public abstract void handleStartActivity(IBinder token, + public abstract void handleStartActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); /** Get package info. */ @@ -176,7 +181,7 @@ public abstract class ClientTransactionHandler { * Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the * provided token. */ - public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token); + public abstract ActivityClientRecord getActivityClient(IBinder token); /** * Prepare activity relaunch to update internal bookkeeping. This is used to track multiple @@ -191,7 +196,7 @@ public abstract class ClientTransactionHandler { * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during * relaunch, or {@code null} if relaunch cancelled. */ - public abstract ActivityThread.ActivityClientRecord prepareRelaunchActivity(IBinder token, + public abstract ActivityClientRecord prepareRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config, boolean preserveWindow); @@ -200,14 +205,15 @@ public abstract class ClientTransactionHandler { * @param r Activity client record prepared for relaunch. * @param pendingActions Pending actions to be used on later stages of activity transaction. * */ - public abstract void handleRelaunchActivity(ActivityThread.ActivityClientRecord r, + public abstract void handleRelaunchActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); /** * Report that relaunch request was handled. - * @param token Target activity token. + * @param r Target activity record. * @param pendingActions Pending actions initialized on earlier stages of activity transaction. * Used to check if we should report relaunch to WM. * */ - public abstract void reportRelaunch(IBinder token, PendingTransactionActions pendingActions); + public abstract void reportRelaunch(@NonNull ActivityClientRecord r, + PendingTransactionActions pendingActions); } diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 7cdf85e0a6b8..d61c5d5ccd3d 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -49,6 +49,7 @@ public class LocalActivityManager { private static final String TAG = "LocalActivityManager"; private static final boolean localLOGV = false; + // TODO(b/127877792): try to remove this and use {@code ActivityClientRecord} instead. // Internal token for an Activity being managed by LocalActivityManager. private static class LocalActivityRecord extends Binder { LocalActivityRecord(String _id, Intent _intent) { @@ -136,7 +137,7 @@ public class LocalActivityManager { // startActivity() has not yet been called, so nothing to do. return; } - + if (r.curState == INITIALIZING) { // Get the lastNonConfigurationInstance for the activity HashMap<String, Object> lastNonConfigurationInstances = @@ -177,12 +178,13 @@ public class LocalActivityManager { pendingActions = null; } - mActivityThread.handleStartActivity(r, pendingActions); + mActivityThread.handleStartActivity(clientRecord, pendingActions); r.curState = STARTED; if (desiredState == RESUMED) { if (localLOGV) Log.v(TAG, r.id + ": resuming"); - mActivityThread.performResumeActivity(r, true, "moveToState-INITIALIZING"); + mActivityThread.performResumeActivity(clientRecord, true, + "moveToState-INITIALIZING"); r.curState = RESUMED; } @@ -194,18 +196,21 @@ public class LocalActivityManager { // group's state catches up. return; } - + + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + switch (r.curState) { case CREATED: if (desiredState == STARTED) { if (localLOGV) Log.v(TAG, r.id + ": restarting"); - mActivityThread.performRestartActivity(r, true /* start */); + mActivityThread.performRestartActivity(clientRecord, true /* start */); r.curState = STARTED; } if (desiredState == RESUMED) { if (localLOGV) Log.v(TAG, r.id + ": restarting and resuming"); - mActivityThread.performRestartActivity(r, true /* start */); - mActivityThread.performResumeActivity(r, true, "moveToState-CREATED"); + mActivityThread.performRestartActivity(clientRecord, true /* start */); + mActivityThread.performResumeActivity(clientRecord, true, + "moveToState-CREATED"); r.curState = RESUMED; } return; @@ -214,7 +219,8 @@ public class LocalActivityManager { if (desiredState == RESUMED) { // Need to resume it... if (localLOGV) Log.v(TAG, r.id + ": resuming"); - mActivityThread.performResumeActivity(r, true, "moveToState-STARTED"); + mActivityThread.performResumeActivity(clientRecord, true, + "moveToState-STARTED"); r.instanceState = null; r.curState = RESUMED; } @@ -352,7 +358,8 @@ public class LocalActivityManager { ArrayList<ReferrerIntent> intents = new ArrayList<>(1); intents.add(new ReferrerIntent(intent, mParent.getPackageName())); if (localLOGV) Log.v(TAG, r.id + ": new intent"); - mActivityThread.handleNewIntent(r, intents); + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + mActivityThread.handleNewIntent(clientRecord, intents); r.intent = intent; moveToState(r, mCurState); if (mSingleMode) { @@ -399,7 +406,8 @@ public class LocalActivityManager { performPause(r, finish); } if (localLOGV) Log.v(TAG, r.id + ": destroying"); - mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */, + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + mActivityThread.performDestroyActivity(clientRecord, finish, 0 /* configChanges */, false /* getNonConfigInstance */, "LocalActivityManager::performDestroy"); r.activity = null; r.window = null; @@ -664,7 +672,8 @@ public class LocalActivityManager { for (int i=0; i<N; i++) { LocalActivityRecord r = mActivityArray.get(i); if (localLOGV) Log.v(TAG, r.id + ": destroying"); - mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */, + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + mActivityThread.performDestroyActivity(clientRecord, finishing, 0 /* configChanges */, false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy"); } mActivities.clear(); diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java index 8b52242a6b6c..8a4bee98ca87 100644 --- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -20,6 +20,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.INVALID_DISPLAY; import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.content.res.Configuration; import android.os.IBinder; @@ -32,23 +33,24 @@ import java.util.Objects; * Activity configuration changed callback. * @hide */ -public class ActivityConfigurationChangeItem extends ClientTransactionItem { +public class ActivityConfigurationChangeItem extends ActivityTransactionItem { private Configuration mConfiguration; @Override public void preExecute(android.app.ClientTransactionHandler client, IBinder token) { + final ActivityClientRecord r = getActivityClientRecord(client, token); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. - client.updatePendingActivityConfiguration(token, mConfiguration); + client.updatePendingActivityConfiguration(r, mConfiguration); } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here. Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged"); - client.handleActivityConfigurationChanged(token, mConfiguration, INVALID_DISPLAY); + client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -93,7 +95,7 @@ public class ActivityConfigurationChangeItem extends ClientTransactionItem { mConfiguration = in.readTypedObject(Configuration.CREATOR); } - public static final @android.annotation.NonNull Creator<ActivityConfigurationChangeItem> CREATOR = + public static final @NonNull Creator<ActivityConfigurationChangeItem> CREATOR = new Creator<ActivityConfigurationChangeItem>() { public ActivityConfigurationChangeItem createFromParcel(Parcel in) { return new ActivityConfigurationChangeItem(in); diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java index c9193a9578e7..cadb6606b1be 100644 --- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java +++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java @@ -25,7 +25,7 @@ import java.lang.annotation.RetentionPolicy; * Request for lifecycle state that an activity should reach. * @hide */ -public abstract class ActivityLifecycleItem extends ClientTransactionItem { +public abstract class ActivityLifecycleItem extends ActivityTransactionItem { @IntDef(prefix = { "UNDEFINED", "PRE_", "ON_" }, value = { UNDEFINED, diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index 9844de7b6e88..87ea3f8db39c 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -18,7 +18,8 @@ package android.app.servertransaction; import static android.app.ActivityThread.DEBUG_ORDER; -import android.app.ActivityThread; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; import android.os.IBinder; @@ -36,7 +37,7 @@ import java.util.Objects; * Activity relaunch callback. * @hide */ -public class ActivityRelaunchItem extends ClientTransactionItem { +public class ActivityRelaunchItem extends ActivityTransactionItem { private static final String TAG = "ActivityRelaunchItem"; @@ -50,7 +51,7 @@ public class ActivityRelaunchItem extends ClientTransactionItem { * A record that was properly configured for relaunch. Execution will be cancelled if not * initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}. */ - private ActivityThread.ActivityClientRecord mActivityClientRecord; + private ActivityClientRecord mActivityClientRecord; @Override public void preExecute(ClientTransactionHandler client, IBinder token) { @@ -59,7 +60,7 @@ public class ActivityRelaunchItem extends ClientTransactionItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { if (mActivityClientRecord == null) { if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled"); @@ -73,7 +74,8 @@ public class ActivityRelaunchItem extends ClientTransactionItem { @Override public void postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { - client.reportRelaunch(token, pendingActions); + final ActivityClientRecord r = getActivityClientRecord(client, token); + client.reportRelaunch(r, pendingActions); } // ObjectPoolItem implementation @@ -130,16 +132,16 @@ public class ActivityRelaunchItem extends ClientTransactionItem { mPreserveWindow = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<ActivityRelaunchItem> CREATOR = + public static final @NonNull Creator<ActivityRelaunchItem> CREATOR = new Creator<ActivityRelaunchItem>() { - public ActivityRelaunchItem createFromParcel(Parcel in) { - return new ActivityRelaunchItem(in); - } - - public ActivityRelaunchItem[] newArray(int size) { - return new ActivityRelaunchItem[size]; - } - }; + public ActivityRelaunchItem createFromParcel(Parcel in) { + return new ActivityRelaunchItem(in); + } + + public ActivityRelaunchItem[] newArray(int size) { + return new ActivityRelaunchItem[size]; + } + }; @Override public boolean equals(Object o) { diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index 4e743caccad6..47096a8257e9 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -18,10 +18,11 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; import android.compat.annotation.UnsupportedAppUsage; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -33,7 +34,7 @@ import java.util.Objects; * Activity result delivery callback. * @hide */ -public class ActivityResultItem extends ClientTransactionItem { +public class ActivityResultItem extends ActivityTransactionItem { @UnsupportedAppUsage private List<ResultInfo> mResultInfoList; @@ -45,10 +46,10 @@ public class ActivityResultItem extends ClientTransactionItem { }*/ @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult"); - client.handleSendResult(token, mResultInfoList, "ACTIVITY_RESULT"); + client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -88,7 +89,7 @@ public class ActivityResultItem extends ClientTransactionItem { mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR); } - public static final @android.annotation.NonNull Parcelable.Creator<ActivityResultItem> CREATOR = + public static final @NonNull Parcelable.Creator<ActivityResultItem> CREATOR = new Parcelable.Creator<ActivityResultItem>() { public ActivityResultItem createFromParcel(Parcel in) { return new ActivityResultItem(in); diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java new file mode 100644 index 000000000000..f7d7e9d20ab9 --- /dev/null +++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.servertransaction; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; +import android.app.ClientTransactionHandler; +import android.os.IBinder; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * An activity-targeting callback message to a client that can be scheduled and executed. + * It also provides nullity-free version of + * {@link #execute(ClientTransactionHandler, IBinder, PendingTransactionActions)} for child class + * to inherit. + * + * @see ClientTransaction + * @see ClientTransactionItem + * @see com.android.server.wm.ClientLifecycleManager + * @hide + */ +public abstract class ActivityTransactionItem extends ClientTransactionItem { + @Override + public final void execute(ClientTransactionHandler client, IBinder token, + PendingTransactionActions pendingActions) { + final ActivityClientRecord r = getActivityClientRecord(client, token); + + execute(client, r, pendingActions); + } + + /** + * Like {@link #execute(ClientTransactionHandler, IBinder, PendingTransactionActions)}, + * but take non-null {@link ActivityClientRecord} as a parameter. + */ + @VisibleForTesting(visibility = PACKAGE) + public abstract void execute(@NonNull ClientTransactionHandler client, + @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); + + @NonNull ActivityClientRecord getActivityClientRecord( + @NonNull ClientTransactionHandler client, IBinder token) { + final ActivityClientRecord r = client.getActivityClient(token); + if (r == null) { + throw new IllegalArgumentException("Activity client record must not be null to execute " + + "transaction item"); + } + if (client.getActivity(token) == null) { + throw new IllegalArgumentException("Activity must not be null to execute " + + "transaction item"); + } + return r; + } +} diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java index 3ee761477efd..1611369497e9 100644 --- a/core/java/android/app/servertransaction/DestroyActivityItem.java +++ b/core/java/android/app/servertransaction/DestroyActivityItem.java @@ -18,6 +18,8 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -38,10 +40,10 @@ public class DestroyActivityItem extends ActivityLifecycleItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); - client.handleDestroyActivity(token, mFinished, mConfigChanges, + client.handleDestroyActivity(r, mFinished, mConfigChanges, false /* getNonConfigInstance */, "DestroyActivityItem"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -92,7 +94,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem { mConfigChanges = in.readInt(); } - public static final @android.annotation.NonNull Creator<DestroyActivityItem> CREATOR = + public static final @NonNull Creator<DestroyActivityItem> CREATOR = new Creator<DestroyActivityItem>() { public DestroyActivityItem createFromParcel(Parcel in) { return new DestroyActivityItem(in); diff --git a/core/java/android/app/servertransaction/EnterPipRequestedItem.java b/core/java/android/app/servertransaction/EnterPipRequestedItem.java index b2a1276fa178..b7e81a56afad 100644 --- a/core/java/android/app/servertransaction/EnterPipRequestedItem.java +++ b/core/java/android/app/servertransaction/EnterPipRequestedItem.java @@ -16,20 +16,20 @@ package android.app.servertransaction; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; -import android.os.IBinder; import android.os.Parcel; /** * Request an activity to enter picture-in-picture mode. * @hide */ -public final class EnterPipRequestedItem extends ClientTransactionItem { +public final class EnterPipRequestedItem extends ActivityTransactionItem { @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { - client.handlePictureInPictureRequested(token); + client.handlePictureInPictureRequested(r); } // ObjectPoolItem implementation diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 2e7b6262c785..77457af77340 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -18,6 +18,7 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ProfilerInfo; @@ -163,7 +164,7 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readTypedObject(FixedRotationAdjustments.CREATOR)); } - public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR = + public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<LaunchActivityItem>() { public LaunchActivityItem createFromParcel(Parcel in) { return new LaunchActivityItem(in); diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index 9a457a3aad40..32de53f189b0 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -19,6 +19,7 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.content.res.Configuration; import android.os.IBinder; @@ -31,23 +32,24 @@ import java.util.Objects; * Activity move to a different display message. * @hide */ -public class MoveToDisplayItem extends ClientTransactionItem { +public class MoveToDisplayItem extends ActivityTransactionItem { private int mTargetDisplayId; private Configuration mConfiguration; @Override public void preExecute(ClientTransactionHandler client, IBinder token) { + final ActivityClientRecord r = getActivityClientRecord(client, token); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. - client.updatePendingActivityConfiguration(token, mConfiguration); + client.updatePendingActivityConfiguration(r, mConfiguration); } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay"); - client.handleActivityConfigurationChanged(token, mConfiguration, mTargetDisplayId); + client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -96,7 +98,8 @@ public class MoveToDisplayItem extends ClientTransactionItem { mConfiguration = in.readTypedObject(Configuration.CREATOR); } - public static final @android.annotation.NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<MoveToDisplayItem>() { + public static final @NonNull Creator<MoveToDisplayItem> CREATOR = + new Creator<MoveToDisplayItem>() { public MoveToDisplayItem createFromParcel(Parcel in) { return new MoveToDisplayItem(in); } diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java index 6a4996da38ca..b4e2a7bfa10f 100644 --- a/core/java/android/app/servertransaction/NewIntentItem.java +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -19,9 +19,10 @@ package android.app.servertransaction; import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.compat.annotation.UnsupportedAppUsage; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -35,7 +36,7 @@ import java.util.Objects; * New intent message. * @hide */ -public class NewIntentItem extends ClientTransactionItem { +public class NewIntentItem extends ActivityTransactionItem { @UnsupportedAppUsage private List<ReferrerIntent> mIntents; @@ -47,10 +48,10 @@ public class NewIntentItem extends ClientTransactionItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); - client.handleNewIntent(token, mIntents); + client.handleNewIntent(r, mIntents); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } @@ -94,7 +95,7 @@ public class NewIntentItem extends ClientTransactionItem { mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); } - public static final @android.annotation.NonNull Parcelable.Creator<NewIntentItem> CREATOR = + public static final @NonNull Parcelable.Creator<NewIntentItem> CREATOR = new Parcelable.Creator<NewIntentItem>() { public NewIntentItem createFromParcel(Parcel in) { return new NewIntentItem(in); diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java index f65c843ee76f..cb154e9585e6 100644 --- a/core/java/android/app/servertransaction/PauseActivityItem.java +++ b/core/java/android/app/servertransaction/PauseActivityItem.java @@ -18,8 +18,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; -import android.app.ActivityManager; +import android.annotation.NonNull; import android.app.ActivityTaskManager; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -40,10 +41,10 @@ public class PauseActivityItem extends ActivityLifecycleItem { private boolean mDontReport; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); - client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions, + client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, pendingActions, "PAUSE_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -130,7 +131,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { mDontReport = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<PauseActivityItem> CREATOR = + public static final @NonNull Creator<PauseActivityItem> CREATOR = new Creator<PauseActivityItem>() { public PauseActivityItem createFromParcel(Parcel in) { return new PauseActivityItem(in); diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java index 905076b08e69..d2a156c37c90 100644 --- a/core/java/android/app/servertransaction/ResumeActivityItem.java +++ b/core/java/android/app/servertransaction/ResumeActivityItem.java @@ -18,8 +18,10 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityTaskManager; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -46,10 +48,10 @@ public class ResumeActivityItem extends ActivityLifecycleItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); - client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward, + client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward, "RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -128,7 +130,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { mIsForward = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<ResumeActivityItem> CREATOR = + public static final @NonNull Creator<ResumeActivityItem> CREATOR = new Creator<ResumeActivityItem>() { public ResumeActivityItem createFromParcel(Parcel in) { return new ResumeActivityItem(in); diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java index 4fbe02b9cf76..ae0bd24218fb 100644 --- a/core/java/android/app/servertransaction/StartActivityItem.java +++ b/core/java/android/app/servertransaction/StartActivityItem.java @@ -18,8 +18,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; -import android.os.IBinder; import android.os.Parcel; import android.os.Trace; @@ -32,10 +33,10 @@ public class StartActivityItem extends ActivityLifecycleItem { private static final String TAG = "StartActivityItem"; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem"); - client.handleStartActivity(token, pendingActions); + client.handleStartActivity(r, pendingActions); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -79,7 +80,7 @@ public class StartActivityItem extends ActivityLifecycleItem { // Empty } - public static final @android.annotation.NonNull Creator<StartActivityItem> CREATOR = + public static final @NonNull Creator<StartActivityItem> CREATOR = new Creator<StartActivityItem>() { public StartActivityItem createFromParcel(Parcel in) { return new StartActivityItem(in); diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java index 8668bd49c8f5..7708104da16a 100644 --- a/core/java/android/app/servertransaction/StopActivityItem.java +++ b/core/java/android/app/servertransaction/StopActivityItem.java @@ -18,6 +18,8 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -34,10 +36,10 @@ public class StopActivityItem extends ActivityLifecycleItem { private int mConfigChanges; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); - client.handleStopActivity(token, mConfigChanges, pendingActions, + client.handleStopActivity(r, mConfigChanges, pendingActions, true /* finalStateRequest */, "STOP_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -93,7 +95,7 @@ public class StopActivityItem extends ActivityLifecycleItem { mConfigChanges = in.readInt(); } - public static final @android.annotation.NonNull Creator<StopActivityItem> CREATOR = + public static final @NonNull Creator<StopActivityItem> CREATOR = new Creator<StopActivityItem>() { public StopActivityItem createFromParcel(Parcel in) { return new StopActivityItem(in); diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java index c7e4c3641631..345c1dd336ab 100644 --- a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java +++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java @@ -17,7 +17,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; import android.app.ActivityTaskManager; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -28,15 +30,15 @@ import android.os.Trace; * Top resumed activity changed callback. * @hide */ -public class TopResumedActivityChangeItem extends ClientTransactionItem { +public class TopResumedActivityChangeItem extends ActivityTransactionItem { private boolean mOnTop; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem"); - client.handleTopResumedActivityChanged(token, mOnTop, "topResumedActivityChangeItem"); + client.handleTopResumedActivityChanged(r, mOnTop, "topResumedActivityChangeItem"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -97,16 +99,16 @@ public class TopResumedActivityChangeItem extends ClientTransactionItem { mOnTop = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<TopResumedActivityChangeItem> CREATOR = + public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR = new Creator<TopResumedActivityChangeItem>() { - public TopResumedActivityChangeItem createFromParcel(Parcel in) { - return new TopResumedActivityChangeItem(in); - } - - public TopResumedActivityChangeItem[] newArray(int size) { - return new TopResumedActivityChangeItem[size]; - } - }; + public TopResumedActivityChangeItem createFromParcel(Parcel in) { + return new TopResumedActivityChangeItem(in); + } + + public TopResumedActivityChangeItem[] newArray(int size) { + return new TopResumedActivityChangeItem[size]; + } + }; @Override public boolean equals(Object o) { diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 17fcda587322..3dcf2cb5f13e 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -218,29 +218,29 @@ public class TransactionExecutor { null /* customIntent */); break; case ON_START: - mTransactionHandler.handleStartActivity(r.token, mPendingActions); + mTransactionHandler.handleStartActivity(r, mPendingActions); break; case ON_RESUME: - mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, + mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: - mTransactionHandler.handlePauseActivity(r.token, false /* finished */, + mTransactionHandler.handlePauseActivity(r, false /* finished */, false /* userLeaving */, 0 /* configChanges */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: - mTransactionHandler.handleStopActivity(r.token, 0 /* configChanges */, + mTransactionHandler.handleStopActivity(r, 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: - mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, + mTransactionHandler.handleDestroyActivity(r, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: - mTransactionHandler.performRestartActivity(r.token, false /* start */); + mTransactionHandler.performRestartActivity(r, false /* start */); break; default: throw new IllegalArgumentException("Unexpected lifecycle state: " + state); diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 000e870369db..896a53486311 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -25,14 +25,14 @@ import static android.view.Display.INVALID_DISPLAY; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.testng.Assert.assertFalse; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityThread; +import android.app.ActivityThread.ActivityClientRecord; import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.app.ResourcesManager; @@ -114,11 +114,12 @@ public class ActivityThreadTest { final ActivityThread activityThread = activity.getActivityThread(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { activityThread.executeTransaction(newResumeTransaction(activity)); - assertNull(activityThread.performResumeActivity(activity.getActivityToken(), - true /* finalStateRequest */, "test")); + final ActivityClientRecord r = getActivityClientRecord(activity); + assertFalse(activityThread.performResumeActivity(r, true /* finalStateRequest */, + "test")); - assertNull(activityThread.performResumeActivity(activity.getActivityToken(), - false /* finalStateRequest */, "test")); + assertFalse(activityThread.performResumeActivity(r, false /* finalStateRequest */, + "test")); }); } @@ -244,20 +245,18 @@ public class ActivityThreadTest { newerConfig.orientation = orientation == ORIENTATION_LANDSCAPE ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; newerConfig.seq = seq + 2; - activityThread.updatePendingActivityConfiguration(activity.getActivityToken(), - newerConfig); + final ActivityClientRecord r = getActivityClientRecord(activity); + activityThread.updatePendingActivityConfiguration(r, newerConfig); final Configuration olderConfig = new Configuration(); olderConfig.orientation = orientation; olderConfig.seq = seq + 1; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), - olderConfig, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY); assertEquals(numOfConfig, activity.mNumOfConfigChanges); assertEquals(olderConfig.orientation, activity.mConfig.orientation); - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), - newerConfig, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY); assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges); assertEquals(newerConfig.orientation, activity.mConfig.orientation); }); @@ -274,7 +273,7 @@ public class ActivityThreadTest { config.seq = BASE_SEQ; config.orientation = ORIENTATION_PORTRAIT; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), + activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity), config, INVALID_DISPLAY); }); @@ -335,8 +334,8 @@ public class ActivityThreadTest { config.seq = BASE_SEQ; config.orientation = ORIENTATION_PORTRAIT; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), - config, INVALID_DISPLAY); + final ActivityClientRecord r = getActivityClientRecord(activity); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); }); final int numOfConfig = activity.mNumOfConfigChanges; @@ -513,9 +512,10 @@ public class ActivityThreadTest { startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_ENTER, true); final TestActivity activity = mActivityTestRule.launchActivity(startIntent); final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - activityThread.handlePictureInPictureRequested(activity.getActivityToken()); + activityThread.handlePictureInPictureRequested(r); }); assertTrue(activity.pipRequested()); @@ -528,9 +528,10 @@ public class ActivityThreadTest { startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_SKIP, true); final TestActivity activity = mActivityTestRule.launchActivity(startIntent); final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - activityThread.handlePictureInPictureRequested(activity.getActivityToken()); + activityThread.handlePictureInPictureRequested(r); }); assertTrue(activity.pipRequested()); @@ -541,9 +542,10 @@ public class ActivityThreadTest { public void testHandlePictureInPictureRequested_notOverridden() { final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - activityThread.handlePictureInPictureRequested(activity.getActivityToken()); + activityThread.handlePictureInPictureRequested(r); }); assertTrue(activity.pipRequested()); @@ -552,8 +554,9 @@ public class ActivityThreadTest { } /** - * Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)} - * to try to push activity configuration to the activity for the given sequence number. + * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord, + * Configuration, int)} to try to push activity configuration to the activity for the given + * sequence number. * <p> * It uses orientation to push the configuration and it tries a different orientation if the * first attempt doesn't make through, to rule out the possibility that the previous @@ -566,13 +569,13 @@ public class ActivityThreadTest { */ private int applyConfigurationChange(TestActivity activity, int seq) { final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); final int numOfConfig = activity.mNumOfConfigChanges; Configuration config = new Configuration(); config.orientation = ORIENTATION_PORTRAIT; config.seq = seq; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config, - INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); if (activity.mNumOfConfigChanges > numOfConfig) { return config.seq; @@ -581,12 +584,17 @@ public class ActivityThreadTest { config = new Configuration(); config.orientation = ORIENTATION_LANDSCAPE; config.seq = seq + 1; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config, - INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); return config.seq; } + private static ActivityClientRecord getActivityClientRecord(Activity activity) { + final ActivityThread thread = activity.getActivityThread(); + final IBinder token = activity.getActivityToken(); + return thread.getActivityClient(token); + } + private static ClientTransaction newRelaunchResumeTransaction(Activity activity) { final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null, null, 0, new MergedConfiguration(), false /* preserveWindow */); diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java index 3c32c71cf961..6a0105cf7ff0 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java @@ -32,11 +32,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; @@ -225,6 +226,7 @@ public class TransactionExecutorTests { when(callback2.getPostExecutionState()).thenReturn(UNDEFINED); ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); IBinder token = mock(IBinder.class); + when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class)); ClientTransaction transaction = ClientTransaction.obtain(null /* client */, token /* activityToken */); @@ -236,9 +238,9 @@ public class TransactionExecutorTests { mExecutor.execute(transaction); InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2, stateRequest); - inOrder.verify(callback1, times(1)).execute(eq(mTransactionHandler), eq(token), any()); - inOrder.verify(callback2, times(1)).execute(eq(mTransactionHandler), eq(token), any()); - inOrder.verify(stateRequest, times(1)).execute(eq(mTransactionHandler), eq(token), any()); + inOrder.verify(callback1).execute(eq(mTransactionHandler), eq(token), any()); + inOrder.verify(callback2).execute(eq(mTransactionHandler), eq(token), any()); + inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any()); } @Test @@ -273,7 +275,7 @@ public class TransactionExecutorTests { // The launch transaction should not be executed because its token is in the // to-be-destroyed container. - verify(launchItem, times(0)).execute(any(), any(), any()); + verify(launchItem, never()).execute(any(), any(), any()); // After the destroy transaction has been executed, the token should be removed. mExecutor.execute(destroyTransaction); @@ -282,6 +284,8 @@ public class TransactionExecutorTests { @Test public void testActivityResultRequiredStateResolution() { + when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class)); + PostExecItem postExecItem = new PostExecItem(ON_RESUME); IBinder token = mock(IBinder.class); @@ -292,12 +296,12 @@ public class TransactionExecutorTests { // Verify resolution that should get to onPause mClientRecord.setState(ON_RESUME); mExecutor.executeCallbacks(transaction); - verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction)); + verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction)); // Verify resolution that should get to onStart mClientRecord.setState(ON_STOP); mExecutor.executeCallbacks(transaction); - verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction)); + verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction)); } @Test @@ -433,6 +437,38 @@ public class TransactionExecutorTests { mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME)); } + @Test(expected = IllegalArgumentException.class) + public void testActivityItemNullRecordThrowsException() { + final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class); + when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED); + final IBinder token = mock(IBinder.class); + final ClientTransaction transaction = ClientTransaction.obtain(null /* client */, + token /* activityToken */); + transaction.addCallback(activityItem); + when(mTransactionHandler.getActivityClient(token)).thenReturn(null); + + mExecutor.executeCallbacks(transaction); + } + + @Test + public void testActivityItemExecute() { + final IBinder token = mock(IBinder.class); + final ClientTransaction transaction = ClientTransaction.obtain(null /* client */, + token /* activityToken */); + final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class); + when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED); + transaction.addCallback(activityItem); + final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); + transaction.setLifecycleStateRequest(stateRequest); + when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class)); + + mExecutor.execute(transaction); + + final InOrder inOrder = inOrder(activityItem, stateRequest); + inOrder.verify(activityItem).execute(eq(mTransactionHandler), eq(mClientRecord), any()); + inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any()); + } + private static int[] shuffledArray(int[] inputArray) { final List<Integer> list = Arrays.stream(inputArray).boxed().collect(Collectors.toList()); Collections.shuffle(list); @@ -489,13 +525,13 @@ public class TransactionExecutorTests { public static final Parcelable.Creator<StubItem> CREATOR = new Parcelable.Creator<StubItem>() { - public StubItem createFromParcel(Parcel in) { - return new StubItem(in); - } - - public StubItem[] newArray(int size) { - return new StubItem[size]; - } - }; + public StubItem createFromParcel(Parcel in) { + return new StubItem(in); + } + + public StubItem[] newArray(int size) { + return new StubItem[size]; + } + }; } } diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 1cdc75aa1f40..3f2d0f134443 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -176,27 +176,27 @@ public class ActivityThreadClientTest { } private void startActivity(ActivityClientRecord r) { - mThread.handleStartActivity(r.token, null /* pendingActions */); + mThread.handleStartActivity(r, null /* pendingActions */); } private void resumeActivity(ActivityClientRecord r) { - mThread.handleResumeActivity(r.token, true /* finalStateRequest */, + mThread.handleResumeActivity(r, true /* finalStateRequest */, true /* isForward */, "test"); } private void pauseActivity(ActivityClientRecord r) { - mThread.handlePauseActivity(r.token, false /* finished */, + mThread.handlePauseActivity(r, false /* finished */, false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */, "test"); } private void stopActivity(ActivityClientRecord r) { - mThread.handleStopActivity(r.token, 0 /* configChanges */, + mThread.handleStopActivity(r, 0 /* configChanges */, new PendingTransactionActions(), false /* finalStateRequest */, "test"); } private void destroyActivity(ActivityClientRecord r) { - mThread.handleDestroyActivity(r.token, true /* finishing */, 0 /* configChanges */, + mThread.handleDestroyActivity(r, true /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "test"); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 403f225032e9..8204b36bc551 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -251,7 +251,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AttributeCache; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import com.android.server.SystemServiceManager; import com.android.server.UiThread; import com.android.server.Watchdog; |