Merge "Switch activity relaunch to lifecycler"

This commit is contained in:
TreeHugger Robot
2018-02-08 23:58:15 +00:00
committed by Android (Google) Code Review
11 changed files with 343 additions and 125 deletions

View File

@@ -46,7 +46,6 @@ Landroid/app/ActivityThread$H;->BIND_SERVICE:I
Landroid/app/ActivityThread$H;->CREATE_SERVICE:I
Landroid/app/ActivityThread$H;->EXIT_APPLICATION:I
Landroid/app/ActivityThread$H;->RECEIVER:I
Landroid/app/ActivityThread$H;->RELAUNCH_ACTIVITY:I
Landroid/app/ActivityThread$H;->REMOVE_PROVIDER:I
Landroid/app/ActivityThread$H;->SERVICE_ARGS:I
Landroid/app/ActivityThread$H;->STOP_SERVICE:I

View File

@@ -113,6 +113,7 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.LogPrinter;
import android.util.MergedConfiguration;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -204,7 +205,7 @@ public final class ActivityThread extends ClientTransactionHandler {
private static final boolean DEBUG_SERVICE = false;
public static final boolean DEBUG_MEMORY_TRIM = false;
private static final boolean DEBUG_PROVIDER = false;
private static final boolean DEBUG_ORDER = false;
public static final boolean DEBUG_ORDER = false;
private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
@@ -398,7 +399,6 @@ public final class ActivityThread extends ClientTransactionHandler {
boolean startsNotResumed;
public final boolean isForward;
int pendingConfigChanges;
boolean onlyLocalRequest;
Window mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
@@ -520,7 +520,6 @@ public final class ActivityThread extends ClientTransactionHandler {
sb.append(", startsNotResumed=").append(startsNotResumed);
sb.append(", isForward=").append(isForward);
sb.append(", pendingConfigChanges=").append(pendingConfigChanges);
sb.append(", onlyLocalRequest=").append(onlyLocalRequest);
sb.append(", preserveWindow=").append(mPreserveWindow);
if (activity != null) {
sb.append(", Activity{");
@@ -765,15 +764,6 @@ public final class ActivityThread extends ClientTransactionHandler {
sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
}
@Override
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
Configuration overrideConfig, boolean preserveWindow) {
requestRelaunchActivity(token, pendingResults, pendingNewIntents,
configChanges, notResumed, config, overrideConfig, true, preserveWindow);
}
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
@@ -1531,7 +1521,6 @@ public final class ActivityThread extends ClientTransactionHandler {
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
@@ -1577,7 +1566,6 @@ public final class ActivityThread extends ClientTransactionHandler {
case UNBIND_SERVICE: return "UNBIND_SERVICE";
case DUMP_SERVICE: return "DUMP_SERVICE";
case LOW_MEMORY: return "LOW_MEMORY";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PROFILER_CONTROL: return "PROFILER_CONTROL";
case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
@@ -1611,12 +1599,6 @@ public final class ActivityThread extends ClientTransactionHandler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
@@ -3726,20 +3708,6 @@ public final class ActivityThread extends ClientTransactionHandler {
}
r.activity.performResume(r.startsNotResumed);
synchronized (mResourcesManager) {
// If there is a pending local relaunch that was requested when the activity was
// paused, it will put the activity into paused state when it finally happens.
// Since the activity resumed before being relaunched, we don't want that to
// happen, so we need to clear the request to relaunch paused.
for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
if (relaunching.token == r.token
&& relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
relaunching.startsNotResumed = false;
}
}
}
EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
@@ -3888,14 +3856,12 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(
TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) {
Slog.v(TAG, "Scheduling idle handler for " + r);
}
r.onlyLocalRequest = false;
Looper.myQueue().addIdleHandler(new Idler());
} else {
// If an exception was thrown when trying to resume, then
// just end this activity.
@@ -4586,15 +4552,12 @@ public final class ActivityThread extends ClientTransactionHandler {
mSomeActivitiesChanged = true;
}
/**
* @param preserveWindow Whether the activity should try to reuse the window it created,
* including the decor view after the relaunch.
*/
public final void requestRelaunchActivity(IBinder token,
@Override
public ActivityClientRecord prepareRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
Configuration overrideConfig, boolean fromServer, boolean preserveWindow) {
int configChanges, MergedConfiguration config, boolean preserveWindow) {
ActivityClientRecord target = null;
boolean scheduleRelaunch = false;
synchronized (mResourcesManager) {
for (int i=0; i<mRelaunchingActivities.size(); i++) {
@@ -4616,57 +4579,31 @@ public final class ActivityThread extends ClientTransactionHandler {
r.pendingIntents = pendingNewIntents;
}
}
// For each relaunch request, activity manager expects an answer
if (!r.onlyLocalRequest && fromServer) {
try {
ActivityManager.getService().activityRelaunched(token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
break;
}
}
if (target == null) {
if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null, fromServer:"
+ fromServer);
if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null");
target = new ActivityClientRecord();
target.token = token;
target.pendingResults = pendingResults;
target.pendingIntents = pendingNewIntents;
target.mPreserveWindow = preserveWindow;
if (!fromServer) {
final ActivityClientRecord existing = mActivities.get(token);
if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + existing);
if (existing != null) {
if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: paused= "
+ existing.paused);;
target.startsNotResumed = existing.paused;
target.overrideConfig = existing.overrideConfig;
}
target.onlyLocalRequest = true;
}
mRelaunchingActivities.add(target);
sendMessage(H.RELAUNCH_ACTIVITY, target);
}
if (fromServer) {
target.startsNotResumed = notResumed;
target.onlyLocalRequest = false;
}
if (config != null) {
target.createdConfig = config;
}
if (overrideConfig != null) {
target.overrideConfig = overrideConfig;
scheduleRelaunch = true;
}
target.createdConfig = config.getGlobalConfiguration();
target.overrideConfig = config.getOverrideConfiguration();
target.pendingConfigChanges |= configChanges;
}
return scheduleRelaunch ? target : null;
}
private void handleRelaunchActivity(ActivityClientRecord tmp) {
@Override
public void handleRelaunchActivity(ActivityClientRecord tmp,
PendingTransactionActions pendingActions) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
@@ -4735,18 +4672,10 @@ public final class ActivityThread extends ClientTransactionHandler {
ActivityClientRecord r = mActivities.get(tmp.token);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
if (r == null) {
if (!tmp.onlyLocalRequest) {
try {
ActivityManager.getService().activityRelaunched(tmp.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return;
}
r.activity.mConfigChangeFlags |= configChanges;
r.onlyLocalRequest = tmp.onlyLocalRequest;
r.mPreserveWindow = tmp.mPreserveWindow;
r.activity.mChangingConfigurations = true;
@@ -4763,9 +4692,9 @@ public final class ActivityThread extends ClientTransactionHandler {
// preserved by the server, so we want to notify it that we are preparing to replace
// everything
try {
if (r.mPreserveWindow || r.onlyLocalRequest) {
if (r.mPreserveWindow) {
WindowManagerGlobal.getWindowSession().prepareToReplaceWindows(
r.token, !r.onlyLocalRequest);
r.token, true /* childrenOnly */);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4804,24 +4733,22 @@ public final class ActivityThread extends ClientTransactionHandler {
r.startsNotResumed = tmp.startsNotResumed;
r.overrideConfig = tmp.overrideConfig;
// TODO(lifecycler): Move relaunch to lifecycler.
PendingTransactionActions pendingActions = new PendingTransactionActions();
handleLaunchActivity(r, pendingActions);
handleStartActivity(r, pendingActions);
handleResumeActivity(r.token, false /* clearHide */, r.isForward, "relaunch");
if (r.startsNotResumed) {
performPauseActivity(r, false /* finished */, "relaunch", pendingActions);
}
// Only report a successful relaunch to WindowManager.
pendingActions.setReportRelaunchToWindowManager(true);
}
if (!tmp.onlyLocalRequest) {
try {
ActivityManager.getService().activityRelaunched(r.token);
if (r.window != null) {
r.window.reportActivityRelaunched();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@Override
public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) {
try {
ActivityManager.getService().activityRelaunched(token);
final ActivityClientRecord r = mActivities.get(token);
if (pendingActions.shouldReportRelaunchToWindowManager() && r != null
&& r.window != null) {
r.window.reportActivityRelaunched();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

View File

@@ -21,6 +21,7 @@ import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.MergedConfiguration;
import com.android.internal.content.ReferrerIntent;
@@ -123,6 +124,39 @@ public abstract class ClientTransactionHandler {
*/
public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token);
/**
* Prepare activity relaunch to update internal bookkeeping. This is used to track multiple
* relaunch and config update requests.
* @param token Activity token.
* @param pendingResults Activity results to be delivered.
* @param pendingNewIntents New intent messages to be delivered.
* @param configChanges Mask of configuration changes that have occurred.
* @param config New configuration applied to the activity.
* @param preserveWindow Whether the activity should try to reuse the window it created,
* including the decor view after the relaunch.
* @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,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, MergedConfiguration config, boolean preserveWindow);
/**
* Perform activity relaunch.
* @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,
PendingTransactionActions pendingActions);
/**
* Report that relaunch request was handled.
* @param token Target activity token.
* @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);
/**
* Debugging output.
* @param pw {@link PrintWriter} to write logs to.

View File

@@ -83,9 +83,6 @@ oneway interface IApplicationThread {
int resultCode, in String data, in Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState);
void scheduleLowMemory();
void scheduleRelaunchActivity(IBinder token, in List<ResultInfo> pendingResults,
in List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
in Configuration config, in Configuration overrideConfig, boolean preserveWindow);
void scheduleSleeping(IBinder token, boolean sleeping);
void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType);
void setSchedulingGroup(int group);

View File

@@ -0,0 +1,176 @@
/*
* Copyright 2017 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 android.app.ActivityThread.DEBUG_ORDER;
import android.app.ActivityThread;
import android.app.ClientTransactionHandler;
import android.app.ResultInfo;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Trace;
import android.util.MergedConfiguration;
import android.util.Slog;
import com.android.internal.content.ReferrerIntent;
import java.util.List;
import java.util.Objects;
/**
* Activity relaunch callback.
* @hide
*/
public class ActivityRelaunchItem extends ClientTransactionItem {
private static final String TAG = "ActivityRelaunchItem";
private List<ResultInfo> mPendingResults;
private List<ReferrerIntent> mPendingNewIntents;
private int mConfigChanges;
private MergedConfiguration mConfig;
private boolean mPreserveWindow;
/**
* A record that was properly configured for relaunch. Execution will be cancelled if not
* initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}.
*/
private ActivityThread.ActivityClientRecord mActivityClientRecord;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
}
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
if (mActivityClientRecord == null) {
if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
client.handleRelaunchActivity(mActivityClientRecord, pendingActions);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
client.reportRelaunch(token, pendingActions);
}
// ObjectPoolItem implementation
private ActivityRelaunchItem() {}
/** Obtain an instance initialized with provided params. */
public static ActivityRelaunchItem obtain(List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config,
boolean preserveWindow) {
ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
if (instance == null) {
instance = new ActivityRelaunchItem();
}
instance.mPendingResults = pendingResults;
instance.mPendingNewIntents = pendingNewIntents;
instance.mConfigChanges = configChanges;
instance.mConfig = config;
instance.mPreserveWindow = preserveWindow;
return instance;
}
@Override
public void recycle() {
mPendingResults = null;
mPendingNewIntents = null;
mConfigChanges = 0;
mConfig = null;
mPreserveWindow = false;
mActivityClientRecord = null;
ObjectPool.recycle(this);
}
// Parcelable implementation
/** Write to Parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(mPendingResults, flags);
dest.writeTypedList(mPendingNewIntents, flags);
dest.writeInt(mConfigChanges);
dest.writeTypedObject(mConfig, flags);
dest.writeBoolean(mPreserveWindow);
}
/** Read from Parcel. */
private ActivityRelaunchItem(Parcel in) {
mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR);
mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
mConfigChanges = in.readInt();
mConfig = in.readTypedObject(MergedConfiguration.CREATOR);
mPreserveWindow = in.readBoolean();
}
public static final Creator<ActivityRelaunchItem> CREATOR =
new Creator<ActivityRelaunchItem>() {
public ActivityRelaunchItem createFromParcel(Parcel in) {
return new ActivityRelaunchItem(in);
}
public ActivityRelaunchItem[] newArray(int size) {
return new ActivityRelaunchItem[size];
}
};
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ActivityRelaunchItem other = (ActivityRelaunchItem) o;
return Objects.equals(mPendingResults, other.mPendingResults)
&& Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
&& mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig)
&& mPreserveWindow == other.mPreserveWindow;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + Objects.hashCode(mPendingResults);
result = 31 * result + Objects.hashCode(mPendingNewIntents);
result = 31 * result + mConfigChanges;
result = 31 * result + Objects.hashCode(mConfig);
result = 31 * result + (mPreserveWindow ? 1 : 0);
return result;
}
@Override
public String toString() {
return "ActivityRelaunchItem{pendingResults=" + mPendingResults
+ ",pendingNewIntents=" + mPendingNewIntents + ",configChanges=" + mConfigChanges
+ ",config=" + mConfig + ",preserveWindow" + mPreserveWindow + "}";
}
}

View File

@@ -44,6 +44,7 @@ public class PendingTransactionActions {
private boolean mCallOnPostCreate;
private Bundle mOldState;
private StopInfo mStopInfo;
private boolean mReportRelaunchToWM;
public PendingTransactionActions() {
clear();
@@ -91,6 +92,24 @@ public class PendingTransactionActions {
mStopInfo = stopInfo;
}
/**
* Check if we should report an activity relaunch to WindowManager. We report back for every
* relaunch request to ActivityManager, but only for those that were actually finished to we
* report to WindowManager.
*/
public boolean shouldReportRelaunchToWindowManager() {
return mReportRelaunchToWM;
}
/**
* Set if we should report an activity relaunch to WindowManager. We report back for every
* relaunch request to ActivityManager, but only for those that were actually finished we report
* to WindowManager.
*/
public void setReportRelaunchToWindowManager(boolean reportToWm) {
mReportRelaunchToWM = reportToWm;
}
/** Reports to server about activity stop. */
public static class StopInfo implements Runnable {
private static final String TAG = "ActivityStopInfo";

View File

@@ -17,6 +17,7 @@
package android.app.servertransaction;
import static android.app.servertransaction.TestUtils.config;
import static android.app.servertransaction.TestUtils.mergedConfig;
import static android.app.servertransaction.TestUtils.referrerIntentList;
import static android.app.servertransaction.TestUtils.resultInfoList;
@@ -150,6 +151,25 @@ public class ObjectPoolTests {
assertFalse(item2.equals(emptyItem));
}
@Test
public void testRecycleActivityRelaunchItem() {
ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain(null, null, 0, null, false);
Configuration overrideConfig = new Configuration();
overrideConfig.assetsSeq = 5;
ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
referrerIntentList(), 42, mergedConfig(), true);
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
item.recycle();
assertEquals(item, emptyItem);
ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(resultInfoList(),
referrerIntentList(), 42, mergedConfig(), true);
assertSame(item, item2);
assertFalse(item2.equals(emptyItem));
}
@Test
public void testRecycleMoveToDisplayItem() {
MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, null);

View File

@@ -21,6 +21,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import android.app.ResultInfo;
import android.content.Intent;
import android.content.res.Configuration;
import android.util.MergedConfiguration;
import com.android.internal.content.ReferrerIntent;
@@ -38,6 +39,15 @@ class TestUtils {
return config;
}
static MergedConfiguration mergedConfig() {
Configuration config = config();
Configuration overrideConfig = new Configuration();
overrideConfig.densityDpi = 30;
overrideConfig.screenWidthDp = 40;
overrideConfig.smallestScreenWidthDp = 15;
return new MergedConfiguration(config, overrideConfig);
}
static List<ResultInfo> resultInfoList() {
String resultWho1 = "resultWho1";
int requestCode1 = 7;

View File

@@ -17,6 +17,7 @@
package android.app.servertransaction;
import static android.app.servertransaction.TestUtils.config;
import static android.app.servertransaction.TestUtils.mergedConfig;
import static android.app.servertransaction.TestUtils.referrerIntentList;
import static android.app.servertransaction.TestUtils.resultInfoList;
@@ -27,7 +28,6 @@ import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.IUiAutomationConnection;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -53,7 +53,6 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import org.junit.Before;
import org.junit.Test;
@@ -242,6 +241,22 @@ public class TransactionParcelTests {
assertTrue(item.equals(result));
}
@Test
public void testRelaunch() {
// Write to parcel
Configuration overrideConfig = new Configuration();
overrideConfig.assetsSeq = 5;
ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
referrerIntentList(), 35, mergedConfig(), true);
writeAndPrepareForReading(item);
// Read from parcel and assert
ActivityRelaunchItem result = ActivityRelaunchItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
assertTrue(item.equals(result));
}
@Test
public void testPause() {
// Write to parcel
@@ -434,12 +449,6 @@ public class TransactionParcelTests {
public void scheduleLowMemory() throws RemoteException {
}
@Override
public void scheduleRelaunchActivity(IBinder iBinder, List<ResultInfo> list,
List<ReferrerIntent> list1, int i, boolean b, Configuration configuration,
Configuration configuration1, boolean b1) throws RemoteException {
}
@Override
public void scheduleSleeping(IBinder iBinder, boolean b) throws RemoteException {
}

View File

@@ -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;
@@ -2370,6 +2375,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
if (state == 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);
@@ -2559,12 +2573,23 @@ 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();
}
final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
transaction.addCallback(callbackItem);
transaction.setLifecycleStateRequest(lifecycleItem);
service.mLifecycleManager.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);

View File

@@ -1509,6 +1509,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
}
// TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
// so updating the state should be done accordingly.
if (andResume && readyToResume()) {
// As part of the process of launching, ActivityThread also performs
// a resume.