summaryrefslogtreecommitdiff
path: root/com/android/server/am/ActivityRecord.java
diff options
context:
space:
mode:
Diffstat (limited to 'com/android/server/am/ActivityRecord.java')
-rw-r--r--com/android/server/am/ActivityRecord.java294
1 files changed, 226 insertions, 68 deletions
diff --git a/com/android/server/am/ActivityRecord.java b/com/android/server/am/ActivityRecord.java
index 3bef8779..1af41144 100644
--- a/com/android/server/am/ActivityRecord.java
+++ b/com/android/server/am/ActivityRecord.java
@@ -112,16 +112,16 @@ import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
import static com.android.server.am.TaskPersister.DEBUG;
import static com.android.server.am.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.proto.ActivityRecordProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.ActivityRecordProto.FRONT_OF_TASK;
-import static com.android.server.am.proto.ActivityRecordProto.IDENTIFIER;
-import static com.android.server.am.proto.ActivityRecordProto.PROC_ID;
-import static com.android.server.am.proto.ActivityRecordProto.STATE;
-import static com.android.server.am.proto.ActivityRecordProto.VISIBLE;
+import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
+import static com.android.server.am.ActivityRecordProto.PROC_ID;
+import static com.android.server.am.ActivityRecordProto.STATE;
+import static com.android.server.am.ActivityRecordProto.VISIBLE;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.wm.proto.IdentifierProto.HASH_CODE;
-import static com.android.server.wm.proto.IdentifierProto.TITLE;
-import static com.android.server.wm.proto.IdentifierProto.USER_ID;
+import static com.android.server.wm.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.IdentifierProto.TITLE;
+import static com.android.server.wm.IdentifierProto.USER_ID;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -133,11 +133,16 @@ import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.ResultInfo;
+import android.app.servertransaction.ActivityLifecycleItem;
+import android.app.servertransaction.ActivityRelaunchItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.MoveToDisplayItem;
import android.app.servertransaction.MultiWindowModeChangeItem;
import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.PipModeChangeItem;
+import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.WindowVisibilityItem;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.content.ComponentName;
@@ -225,11 +230,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
+ private static final int MAX_STORED_STATE_TRANSITIONS = 5;
+
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
AppWindowContainerController mWindowContainerController;
final ActivityInfo info; // all about me
- final ApplicationInfo appInfo; // information about activity's app
+ // TODO: This is duplicated state already contained in info.applicationInfo - remove
+ ApplicationInfo appInfo; // information about activity's app
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
final String launchedFromPackage; // always the package who started the activity.
@@ -283,7 +291,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
UriPermissionOwner uriPermissions; // current special URI access perms.
ProcessRecord app; // if non-null, hosting application
- ActivityState state; // current state we are in
+ private ActivityState mState; // current state we are in
Bundle icicle; // last saved activity state
PersistableBundle persistentState; // last persistently saved activity state
// TODO: See if this is still needed.
@@ -356,11 +364,33 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private boolean mTurnScreenOn;
/**
- * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
+ * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)}
*/
private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
+ private final ArrayList<StateTransition> mRecentTransitions = new ArrayList<>();
+
+ // TODO(b/71506345): Remove once issue has been resolved.
+ private static class StateTransition {
+ final long time;
+ final ActivityState prev;
+ final ActivityState state;
+ final String reason;
+
+ StateTransition(ActivityState prev, ActivityState state, String reason) {
+ time = System.currentTimeMillis();
+ this.prev = prev;
+ this.state = state;
+ this.reason = reason;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + prev + "->" + state + ":" + reason + "@" + time + "]";
+ }
+ }
+
private static String startingWindowStateToString(int state) {
switch (state) {
case STARTING_WINDOW_NOT_SHOWN:
@@ -375,7 +405,18 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
String getLifecycleDescription(String reason) {
- return "packageName=" + packageName + ", state=" + state + ", reason=" + reason;
+ StringBuilder transitionBuilder = new StringBuilder();
+
+ for (int i = 0, size = mRecentTransitions.size(); i < size; ++i) {
+ transitionBuilder.append(mRecentTransitions.get(i));
+ if (i + 1 < size) {
+ transitionBuilder.append(",");
+ }
+ }
+
+ return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
+ + ", package=" + packageName + ", state=" + mState + ", reason=" + reason
+ + ", time=" + System.currentTimeMillis() + " transitions=" + transitionBuilder;
}
void dump(PrintWriter pw, String prefix) {
@@ -496,7 +537,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
pw.println();
pw.print(prefix); pw.print("haveState="); pw.print(haveState);
pw.print(" icicle="); pw.println(icicle);
- pw.print(prefix); pw.print("state="); pw.print(state);
+ pw.print(prefix); pw.print("state="); pw.print(mState);
pw.print(" stopped="); pw.print(stopped);
pw.print(" delayedResume="); pw.print(delayedResume);
pw.print(" finishing="); pw.println(finishing);
@@ -565,6 +606,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
}
+ void updateApplicationInfo(ApplicationInfo aInfo) {
+ appInfo = aInfo;
+ info.applicationInfo = aInfo;
+ }
+
private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp);
}
@@ -625,7 +671,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
"Reporting activity moved to display" + ", activityRecord=" + this
+ ", displayId=" + displayId + ", config=" + config);
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
MoveToDisplayItem.obtain(displayId, config));
} catch (RemoteException e) {
// If process died, whatever.
@@ -643,7 +689,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
+ config);
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
ActivityConfigurationChangeItem.obtain(config));
} catch (RemoteException e) {
// If process died, whatever.
@@ -670,7 +716,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
try {
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode,
overrideConfig));
} catch (Exception e) {
@@ -698,7 +744,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
overrideConfig));
} catch (Exception e) {
@@ -834,7 +880,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
resultTo = _resultTo;
resultWho = _resultWho;
requestCode = _reqCode;
- state = INITIALIZING;
+ setState(INITIALIZING, "ActivityRecord ctor");
frontOfTask = false;
launchFailed = false;
stopped = false;
@@ -993,6 +1039,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
void removeWindowContainer() {
+ // Do not try to remove a window container if we have already removed it.
+ if (mWindowContainerController == null) {
+ return;
+ }
+
// Resume key dispatching if it is currently paused before we remove the container.
resumeKeyDispatchingLocked();
@@ -1148,6 +1199,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
boolean isFocusable() {
+ if (inSplitScreenPrimaryWindowingMode() && mStackSupervisor.mIsDockMinimized) {
+ return false;
+ }
return getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable();
}
@@ -1252,7 +1306,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return false;
}
- switch (state) {
+ switch (mState) {
case RESUMED:
// When visible, allow entering PiP if the app is not locked. If it is over the
// keyguard, then we will prompt to unlock in the caller before entering PiP.
@@ -1378,13 +1432,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// - It is currently resumed or paused. i.e. it is currently visible to the user and we want
// the user to see the visual effects caused by the intent delivery now.
// - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
- if ((state == RESUMED || state == PAUSED
+ if ((mState == RESUMED || mState == PAUSED
|| isTopActivityWhileSleeping) && app != null && app.thread != null) {
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
- NewIntentItem.obtain(ar, state == PAUSED));
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+ NewIntentItem.obtain(ar, mState == PAUSED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1495,7 +1549,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
break;
}
- pendingOptions = null;
+
+ if (task == null) {
+ clearOptionsLocked(false /* withAbort */);
+ } else {
+ // This will clear the options for all the ActivityRecords for this Task.
+ task.clearAllPendingOptions();
+ }
}
}
@@ -1504,10 +1564,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
void clearOptionsLocked() {
- if (pendingOptions != null) {
+ clearOptionsLocked(true /* withAbort */);
+ }
+
+ void clearOptionsLocked(boolean withAbort) {
+ if (withAbort && pendingOptions != null) {
pendingOptions.abort();
- pendingOptions = null;
}
+ pendingOptions = null;
}
ActivityOptions takeOptionsLocked() {
@@ -1566,6 +1630,65 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
+ void setState(ActivityState state, String reason) {
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ + " to:" + state + " reason:" + reason);
+
+ if (state == mState) {
+ // No need to do anything if state doesn't change.
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state);
+ return;
+ }
+
+ final ActivityState prev = mState;
+ mState = state;
+
+ if (mRecentTransitions.size() == MAX_STORED_STATE_TRANSITIONS) {
+ mRecentTransitions.remove(0);
+ }
+
+ mRecentTransitions.add(new StateTransition(prev, state, reason));
+
+ final TaskRecord parent = getTask();
+
+ if (parent != null) {
+ parent.onActivityStateChanged(this, state, reason);
+ }
+ }
+
+ ActivityState getState() {
+ return mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in the specified state.
+ */
+ boolean isState(ActivityState state) {
+ return state == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2) {
+ return state1 == mState || state2 == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3) {
+ return state1 == mState || state2 == mState || state3 == mState;
+ }
+
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
+ ActivityState state4) {
+ return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
+ }
+
void notifyAppResumed(boolean wasStopped) {
mWindowContainerController.notifyAppResumed(wasStopped);
}
@@ -1595,9 +1718,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
void makeVisibleIfNeeded(ActivityRecord starting) {
// This activity is not currently visible, but is running. Tell it to become visible.
- if (state == RESUMED || this == starting) {
+ if (mState == RESUMED || this == starting) {
if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
- "Not making visible, r=" + this + " state=" + state + " starting=" + starting);
+ "Not making visible, r=" + this + " state=" + mState + " starting=" + starting);
return;
}
@@ -1613,28 +1736,35 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
setVisible(true);
sleeping = false;
app.pendingUiClean = true;
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
WindowVisibilityItem.obtain(true /* showWindow */));
// The activity may be waiting for stop, but that is no longer appropriate for it.
mStackSupervisor.mStoppingActivities.remove(this);
mStackSupervisor.mGoingToSleepActivities.remove(this);
- // If the activity is stopped or stopping, cycle to the paused state.
- if (state == STOPPED || state == STOPPING) {
+ // If the activity is stopped or stopping, cycle to the paused state. We avoid doing
+ // this when there is an activity waiting to become translucent as the extra binder
+ // calls will lead to noticeable jank. A later call to
+ // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to the proper
+ // paused state. We also avoid doing this for the activity the stack supervisor
+ // considers the resumed activity, as normal means will bring the activity from STOPPED
+ // to RESUMED. Adding PAUSING in this scenario will lead to double lifecycles.
+ if (isState(STOPPED, STOPPING) && stack.mTranslucentActivityWaiting == null
+ && mStackSupervisor.getResumedActivityLocked() != this) {
// Capture reason before state change
final String reason = getLifecycleDescription("makeVisibleIfNeeded");
// An activity must be in the {@link PAUSING} state for the system to validate
// the move to {@link PAUSED}.
- state = PAUSING;
- service.mLifecycleManager.scheduleTransaction(app.thread, appToken,
+ setState(PAUSING, "makeVisibleIfNeeded");
+ service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */)
.setDescription(reason));
}
} catch (Exception e) {
// Just skip on any failure; we'll make it visible when it next restarts.
- Slog.w(TAG, "Exception thrown making visibile: " + intent.getComponent(), e);
+ Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e);
}
handleAlreadyVisible();
}
@@ -1647,7 +1777,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
} catch(RemoteException e) {
}
- return state == RESUMED;
+ return mState == RESUMED;
}
static void activityResumedLocked(IBinder token) {
@@ -1695,7 +1825,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
resumeKeyDispatchingLocked();
final ActivityStack stack = getStack();
- stack.mNoAnimActivities.clear();
+ mStackSupervisor.mNoAnimActivities.clear();
// Mark the point when the activity is resuming
// TODO: To be more accurate, the mark should be before the onCreate,
@@ -1721,7 +1851,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
CharSequence description) {
final ActivityStack stack = getStack();
- if (state != STOPPING) {
+ if (mState != STOPPING) {
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
return;
@@ -1744,7 +1874,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
stopped = true;
- state = STOPPED;
+ setState(STOPPED, "activityStoppedLocked");
mWindowContainerController.notifyAppStopped();
@@ -1894,14 +2024,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
public void onStartingWindowDrawn(long timestamp) {
synchronized (service) {
mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
- getStackId(), timestamp);
+ getWindowingMode(), timestamp);
}
}
@Override
public void onWindowsDrawn(long timestamp) {
synchronized (service) {
- mStackSupervisor.getActivityMetricsLogger().notifyWindowsDrawn(getStackId(), timestamp);
+ mStackSupervisor.getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(),
+ timestamp);
if (displayStartTime != 0) {
reportLaunchTimeLocked(timestamp);
}
@@ -1983,7 +2114,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this) || stopped) {
final ActivityStack stack = mStackSupervisor.getFocusedStack();
// Try to use the one which is closest to top.
- ActivityRecord r = stack.mResumedActivity;
+ ActivityRecord r = stack.getResumedActivity();
if (r == null) {
r = stack.mPausingActivity;
}
@@ -2013,8 +2144,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
* currently pausing, or is resumed.
*/
public boolean isInterestingToUserLocked() {
- return visible || nowVisible || state == PAUSING ||
- state == RESUMED;
+ return visible || nowVisible || mState == PAUSING || mState == RESUMED;
}
void setSleeping(boolean _sleeping) {
@@ -2076,13 +2206,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
final boolean isDestroyable() {
- if (finishing || app == null || state == DESTROYING
- || state == DESTROYED) {
+ if (finishing || app == null) {
// This would be redundant.
return false;
}
final ActivityStack stack = getStack();
- if (stack == null || this == stack.mResumedActivity || this == stack.mPausingActivity
+ if (stack == null || this == stack.getResumedActivity() || this == stack.mPausingActivity
|| !haveState || !stopped) {
// We're not ready for this kind of thing.
return false;
@@ -2143,7 +2272,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal(),
+ mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
@@ -2297,13 +2426,27 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
outBounds.offsetTo(left, 0 /* top */);
}
+ boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
+ return ensureActivityConfiguration(globalChanges, preserveWindow,
+ false /* ignoreStopState */);
+ }
+
/**
- * Make sure the given activity matches the current configuration. Returns false if the activity
- * had to be destroyed. Returns true if the configuration is the same, or the activity will
- * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
- * correct configuration and all other bookkeeping is handled.
+ * Make sure the given activity matches the current configuration. Ensures the HistoryRecord
+ * is updated with the correct configuration and all other bookkeeping is handled.
+ *
+ * @param globalChanges The changes to the global configuration.
+ * @param preserveWindow If the activity window should be preserved on screen if the activity
+ * is relaunched.
+ * @param ignoreStopState If we should try to relaunch the activity even if it is in the stopped
+ * state. This is useful for the case where we know the activity will be
+ * visible soon and we want to ensure its configuration before we make it
+ * visible.
+ * @return True if the activity was relaunched and false if it wasn't relaunched because we
+ * can't or the app handles the specific configuration that is changing.
*/
- boolean ensureActivityConfigurationLocked(int globalChanges, boolean preserveWindow) {
+ boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
+ boolean ignoreStopState) {
final ActivityStack stack = getStack();
if (stack.mConfigWillChange) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -2319,8 +2462,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return true;
}
- // Skip updating configuration for activity that are stopping or stopped.
- if (state == STOPPING || state == STOPPED) {
+ if (!ignoreStopState && (mState == STOPPING || mState == STOPPED)) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check stopped or stopping: " + this);
return true;
@@ -2370,6 +2512,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
+ if (mState == INITIALIZING) {
+ // No need to relaunch or schedule new config for activity that hasn't been launched
+ // yet. We do, however, return after applying the config to activity record, so that
+ // it will use it for launch transaction.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Skipping config check for initializing activity: " + this);
+ return true;
+ }
+
if (changes == 0 && !forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration no differences in " + this);
@@ -2414,7 +2565,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + this);
stack.destroyActivityLocked(this, true, "config");
- } else if (state == PAUSING) {
+ } else if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
// do anything now, but just flag that it needs to be restarted when done pausing.
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -2422,7 +2573,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
deferRelaunchUntilPaused = true;
preserveWindowOnDeferredRelaunch = preserveWindow;
return true;
- } else if (state == RESUMED) {
+ } else if (mState == RESUMED) {
// Try to optimize this case: the configuration is changing and we need to restart
// the top, resumed activity. Instead of doing the normal handshaking, just say
// "restart!".
@@ -2559,12 +2710,24 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
+ " callers=" + Debug.getCallers(6));
forceNewConfig = false;
mStackSupervisor.activityRelaunchingLocked(this);
- app.thread.scheduleRelaunchActivity(appToken, pendingResults, pendingNewIntents,
- configChangeFlags, !andResume,
- new Configuration(service.getGlobalConfiguration()),
- new Configuration(getMergedOverrideConfiguration()), preserveWindow);
+ final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
+ pendingNewIntents, configChangeFlags,
+ new MergedConfiguration(service.getGlobalConfiguration(),
+ getMergedOverrideConfiguration()),
+ preserveWindow);
+ final ActivityLifecycleItem lifecycleItem;
+ if (andResume) {
+ lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
+ } else {
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(getLifecycleDescription("relaunchActivityLocked"));
+ }
+ final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
+ transaction.addCallback(callbackItem);
+ transaction.setLifecycleStateRequest(lifecycleItem);
+ service.getLifecycleManager().scheduleTransaction(transaction);
// Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
- // pass in 'andResume' if this activity is currently resumed, which implies we aren't
+ // request resume if this activity is currently resumed, which implies we aren't
// sleeping.
} catch (RemoteException e) {
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
@@ -2580,12 +2743,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
service.showAskCompatModeDialogLocked(this);
} else {
service.mHandler.removeMessages(PAUSE_TIMEOUT_MSG, this);
- state = PAUSED;
- // if the app is relaunched when it's stopped, and we're not resuming,
- // put it back into stopped state.
- if (stopped) {
- getStack().addToStopping(this, true /* scheduleIdle */, false /* idleDelayed */);
- }
+ setState(PAUSED, "relaunchActivityLocked");
}
configChangeFlags = 0;
@@ -2824,7 +2982,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
writeIdentifierToProto(proto, IDENTIFIER);
- proto.write(STATE, state.toString());
+ proto.write(STATE, mState.toString());
proto.write(VISIBLE, visible);
proto.write(FRONT_OF_TASK, frontOfTask);
if (app != null) {