diff options
26 files changed, 1861 insertions, 375 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 21e454f11ebc..1d0765d51779 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -23,6 +23,8 @@ import android.annotation.Nullable; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; +import android.app.servertransaction.ActivityResultItem; +import android.app.servertransaction.ClientTransaction; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; import android.content.ComponentName; @@ -174,7 +176,7 @@ final class RemoteServiceException extends AndroidRuntimeException { * * {@hide} */ -public final class ActivityThread { +public final class ActivityThread extends ClientTransactionHandler { /** @hide */ public static final String TAG = "ActivityThread"; private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565; @@ -401,8 +403,8 @@ public final class ActivityThread { throw new IllegalStateException( "Received config update for non-existing activity"); } - activity.mMainThread.handleActivityConfigurationChanged( - new ActivityConfigChangeData(token, overrideConfig), newDisplayId); + activity.mMainThread.handleActivityConfigurationChanged(token, overrideConfig, + newDisplayId); }; } @@ -469,16 +471,6 @@ public final class ActivityThread { } } - static final class NewIntentData { - List<ReferrerIntent> intents; - IBinder token; - boolean andPause; - public String toString() { - return "NewIntentData{intents=" + intents + " token=" + token - + " andPause=" + andPause +"}"; - } - } - static final class ReceiverData extends BroadcastReceiver.PendingResult { public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, IBinder token, int sendingUser) { @@ -644,14 +636,6 @@ public final class ActivityThread { String[] args; } - static final class ResultData { - IBinder token; - List<ResultInfo> results; - public String toString() { - return "ResultData{token=" + token + " results" + results + "}"; - } - } - static final class ContextCleanupInfo { ContextImpl context; String what; @@ -679,15 +663,6 @@ public final class ActivityThread { int flags; } - static final class ActivityConfigChangeData { - final IBinder activityToken; - final Configuration overrideConfig; - public ActivityConfigChangeData(IBinder token, Configuration config) { - activityToken = token; - overrideConfig = config; - } - } - private class ApplicationThread extends IApplicationThread.Stub { private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s"; @@ -702,93 +677,10 @@ public final class ActivityThread { } } - public final void schedulePauseActivity(IBinder token, boolean finished, - boolean userLeaving, int configChanges, boolean dontReport) { - int seq = getLifecycleSeq(); - if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this - + " operation received seq: " + seq); - sendMessage( - finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY, - token, - (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0), - configChanges, - seq); - } - - public final void scheduleStopActivity(IBinder token, boolean showWindow, - int configChanges) { - int seq = getLifecycleSeq(); - if (DEBUG_ORDER) Slog.d(TAG, "stopActivity " + ActivityThread.this - + " operation received seq: " + seq); - sendMessage( - showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE, - token, 0, configChanges, seq); - } - - public final void scheduleWindowVisibility(IBinder token, boolean showWindow) { - sendMessage( - showWindow ? H.SHOW_WINDOW : H.HIDE_WINDOW, - token); - } - public final void scheduleSleeping(IBinder token, boolean sleeping) { sendMessage(H.SLEEPING, token, sleeping ? 1 : 0); } - public final void scheduleResumeActivity(IBinder token, int processState, - boolean isForward, Bundle resumeArgs) { - int seq = getLifecycleSeq(); - if (DEBUG_ORDER) Slog.d(TAG, "resumeActivity " + ActivityThread.this - + " operation received seq: " + seq); - updateProcessState(processState, false); - sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0, 0, seq); - } - - public final void scheduleSendResult(IBinder token, List<ResultInfo> results) { - ResultData res = new ResultData(); - res.token = token; - res.results = results; - sendMessage(H.SEND_RESULT, res); - } - - // we use token to identify this activity without having to send the - // activity itself back to the activity manager. (matters more with ipc) - @Override - public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, Configuration curConfig, Configuration overrideConfig, - CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, - int procState, Bundle state, PersistableBundle persistentState, - List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, - boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { - - updateProcessState(procState, false); - - ActivityClientRecord r = new ActivityClientRecord(); - - r.token = token; - r.ident = ident; - r.intent = intent; - r.referrer = referrer; - r.voiceInteractor = voiceInteractor; - r.activityInfo = info; - r.compatInfo = compatInfo; - r.state = state; - r.persistentState = persistentState; - - r.pendingResults = pendingResults; - r.pendingIntents = pendingNewIntents; - - r.startsNotResumed = notResumed; - r.isForward = isForward; - - r.profilerInfo = profilerInfo; - - r.overrideConfig = overrideConfig; - updatePendingConfiguration(curConfig); - - sendMessage(H.LAUNCH_ACTIVITY, r); - } - @Override public final void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, @@ -798,22 +690,6 @@ public final class ActivityThread { configChanges, notResumed, config, overrideConfig, true, preserveWindow); } - public final void scheduleNewIntent( - List<ReferrerIntent> intents, IBinder token, boolean andPause) { - NewIntentData data = new NewIntentData(); - data.intents = intents; - data.token = token; - data.andPause = andPause; - - sendMessage(H.NEW_INTENT, data); - } - - public final void scheduleDestroyActivity(IBinder token, boolean finishing, - int configChanges) { - sendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0, - configChanges); - } - public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, boolean sync, int sendingUser, int processState) { @@ -949,11 +825,6 @@ public final class ActivityThread { sendMessage(H.SUICIDE, null); } - public void scheduleConfigurationChanged(Configuration config) { - updatePendingConfiguration(config); - sendMessage(H.CONFIGURATION_CHANGED, config); - } - public void scheduleApplicationInfoChanged(ApplicationInfo ai) { sendMessage(H.APPLICATION_INFO_CHANGED, ai); } @@ -1016,20 +887,6 @@ public final class ActivityThread { } @Override - public void scheduleActivityConfigurationChanged( - IBinder token, Configuration overrideConfig) { - sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, - new ActivityConfigChangeData(token, overrideConfig)); - } - - @Override - public void scheduleActivityMovedToDisplay(IBinder token, int displayId, - Configuration overrideConfig) { - sendMessage(H.ACTIVITY_MOVED_TO_DISPLAY, - new ActivityConfigChangeData(token, overrideConfig), displayId); - } - - @Override public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) { sendMessage(H.PROFILER_CONTROL, profilerInfo, start ? 1 : 0, profileType); } @@ -1427,26 +1284,6 @@ public final class ActivityThread { } @Override - public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, - Configuration overrideConfig) throws RemoteException { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = token; - args.arg2 = overrideConfig; - args.argi1 = isInMultiWindowMode ? 1 : 0; - sendMessage(H.MULTI_WINDOW_MODE_CHANGED, args); - } - - @Override - public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode, - Configuration overrideConfig) throws RemoteException { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = token; - args.arg2 = overrideConfig; - args.argi1 = isInPipMode ? 1 : 0; - sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, args); - } - - @Override public void scheduleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor voiceInteractor) throws RemoteException { SomeArgs args = SomeArgs.obtain(); @@ -1459,28 +1296,33 @@ public final class ActivityThread { public void handleTrustStorageUpdate() { NetworkSecurityPolicy.getInstance().handleTrustStorageUpdate(); } + + @Override + public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { + ActivityThread.this.scheduleTransaction(transaction); + } + } + + @Override + public void updatePendingConfiguration(Configuration config) { + mAppThread.updatePendingConfiguration(config); + } + + @Override + public void updateProcessState(int processState, boolean fromIpc) { + mAppThread.updateProcessState(processState, fromIpc); } - private int getLifecycleSeq() { + @Override + public int getLifecycleSeq() { synchronized (mResourcesManager) { return mLifecycleSeq++; } } - private class H extends Handler { - public static final int LAUNCH_ACTIVITY = 100; - public static final int PAUSE_ACTIVITY = 101; - public static final int PAUSE_ACTIVITY_FINISHING= 102; - public static final int STOP_ACTIVITY_SHOW = 103; - public static final int STOP_ACTIVITY_HIDE = 104; - public static final int SHOW_WINDOW = 105; - public static final int HIDE_WINDOW = 106; - public static final int RESUME_ACTIVITY = 107; - public static final int SEND_RESULT = 108; - public static final int DESTROY_ACTIVITY = 109; + class H extends Handler { public static final int BIND_APPLICATION = 110; public static final int EXIT_APPLICATION = 111; - public static final int NEW_INTENT = 112; public static final int RECEIVER = 113; public static final int CREATE_SERVICE = 114; public static final int SERVICE_ARGS = 115; @@ -1493,7 +1335,6 @@ public final class ActivityThread { 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 ACTIVITY_CONFIGURATION_CHANGED = 125; public static final int RELAUNCH_ACTIVITY = 126; public static final int PROFILER_CONTROL = 127; public static final int CREATE_BACKUP_AGENT = 128; @@ -1518,30 +1359,17 @@ public final class ActivityThread { public static final int ENTER_ANIMATION_COMPLETE = 149; public static final int START_BINDER_TRACKING = 150; public static final int STOP_BINDER_TRACKING_AND_DUMP = 151; - public static final int MULTI_WINDOW_MODE_CHANGED = 152; - public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153; public static final int LOCAL_VOICE_INTERACTION_STARTED = 154; public static final int ATTACH_AGENT = 155; public static final int APPLICATION_INFO_CHANGED = 156; - public static final int ACTIVITY_MOVED_TO_DISPLAY = 157; public static final int RUN_ISOLATED_ENTRY_POINT = 158; + public static final int EXECUTE_TRANSACTION = 159; String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { - case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY"; - case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY"; - case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING"; - case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW"; - case STOP_ACTIVITY_HIDE: return "STOP_ACTIVITY_HIDE"; - case SHOW_WINDOW: return "SHOW_WINDOW"; - case HIDE_WINDOW: return "HIDE_WINDOW"; - case RESUME_ACTIVITY: return "RESUME_ACTIVITY"; - case SEND_RESULT: return "SEND_RESULT"; - case DESTROY_ACTIVITY: return "DESTROY_ACTIVITY"; case BIND_APPLICATION: return "BIND_APPLICATION"; case EXIT_APPLICATION: return "EXIT_APPLICATION"; - case NEW_INTENT: return "NEW_INTENT"; case RECEIVER: return "RECEIVER"; case CREATE_SERVICE: return "CREATE_SERVICE"; case SERVICE_ARGS: return "SERVICE_ARGS"; @@ -1553,8 +1381,6 @@ public final class ActivityThread { case UNBIND_SERVICE: return "UNBIND_SERVICE"; case DUMP_SERVICE: return "DUMP_SERVICE"; case LOW_MEMORY: return "LOW_MEMORY"; - case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED"; - case ACTIVITY_MOVED_TO_DISPLAY: return "ACTIVITY_MOVED_TO_DISPLAY"; case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY"; case PROFILER_CONTROL: return "PROFILER_CONTROL"; case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT"; @@ -1577,12 +1403,11 @@ public final class ActivityThread { case INSTALL_PROVIDER: return "INSTALL_PROVIDER"; case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS"; case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE"; - case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED"; - case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED"; case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED"; case ATTACH_AGENT: return "ATTACH_AGENT"; case APPLICATION_INFO_CHANGED: return "APPLICATION_INFO_CHANGED"; case RUN_ISOLATED_ENTRY_POINT: return "RUN_ISOLATED_ENTRY_POINT"; + case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION"; } } return Integer.toString(code); @@ -1590,76 +1415,12 @@ public final class ActivityThread { public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { - case LAUNCH_ACTIVITY: { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); - final ActivityClientRecord r = (ActivityClientRecord) msg.obj; - - r.packageInfo = getPackageInfoNoCheck( - r.activityInfo.applicationInfo, r.compatInfo); - handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } break; 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 PAUSE_ACTIVITY: { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); - SomeArgs args = (SomeArgs) msg.obj; - handlePauseActivity((IBinder) args.arg1, false, - (args.argi1 & USER_LEAVING) != 0, args.argi2, - (args.argi1 & DONT_REPORT) != 0, args.argi3); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } break; - case PAUSE_ACTIVITY_FINISHING: { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); - SomeArgs args = (SomeArgs) msg.obj; - handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0, - args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } break; - case STOP_ACTIVITY_SHOW: { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); - SomeArgs args = (SomeArgs) msg.obj; - handleStopActivity((IBinder) args.arg1, true, args.argi2, args.argi3); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } break; - case STOP_ACTIVITY_HIDE: { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); - SomeArgs args = (SomeArgs) msg.obj; - handleStopActivity((IBinder) args.arg1, false, args.argi2, args.argi3); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } break; - case SHOW_WINDOW: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow"); - handleWindowVisibility((IBinder)msg.obj, true); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; - case HIDE_WINDOW: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow"); - handleWindowVisibility((IBinder)msg.obj, false); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; - case RESUME_ACTIVITY: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); - SomeArgs args = (SomeArgs) msg.obj; - handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true, - args.argi3, "RESUME_ACTIVITY"); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; - case SEND_RESULT: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult"); - handleSendResult((ResultData)msg.obj); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; - case DESTROY_ACTIVITY: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); - handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0, - msg.arg2, false); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; case BIND_APPLICATION: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); AppBindData data = (AppBindData)msg.obj; @@ -1672,11 +1433,6 @@ public final class ActivityThread { } Looper.myLooper().quit(); break; - case NEW_INTENT: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); - handleNewIntent((NewIntentData)msg.obj); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; case RECEIVER: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp"); handleReceiver((ReceiverData)msg.obj); @@ -1708,15 +1464,7 @@ public final class ActivityThread { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CONFIGURATION_CHANGED: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged"); - mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi; - mUpdatingSystemConfig = true; - try { - handleConfigurationChanged((Configuration) msg.obj, null); - } finally { - mUpdatingSystemConfig = false; - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + handleConfigurationChanged((Configuration) msg.obj); break; case CLEAN_UP_CONTEXT: ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj; @@ -1733,18 +1481,6 @@ public final class ActivityThread { handleLowMemory(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; - case ACTIVITY_CONFIGURATION_CHANGED: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged"); - handleActivityConfigurationChanged((ActivityConfigChangeData) msg.obj, - INVALID_DISPLAY); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; - case ACTIVITY_MOVED_TO_DISPLAY: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay"); - handleActivityConfigurationChanged((ActivityConfigChangeData) msg.obj, - msg.arg1 /* displayId */); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; case PROFILER_CONTROL: handleProfilerControl(msg.arg1 != 0, (ProfilerInfo)msg.obj, msg.arg2); break; @@ -1828,16 +1564,6 @@ public final class ActivityThread { case STOP_BINDER_TRACKING_AND_DUMP: handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj); break; - case MULTI_WINDOW_MODE_CHANGED: - handleMultiWindowModeChanged((IBinder) ((SomeArgs) msg.obj).arg1, - ((SomeArgs) msg.obj).argi1 == 1, - (Configuration) ((SomeArgs) msg.obj).arg2); - break; - case PICTURE_IN_PICTURE_MODE_CHANGED: - handlePictureInPictureModeChanged((IBinder) ((SomeArgs) msg.obj).arg1, - ((SomeArgs) msg.obj).argi1 == 1, - (Configuration) ((SomeArgs) msg.obj).arg2); - break; case LOCAL_VOICE_INTERACTION_STARTED: handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1, (IVoiceInteractor) ((SomeArgs) msg.obj).arg2); @@ -1857,6 +1583,9 @@ public final class ActivityThread { handleRunIsolatedEntryPoint((String) ((SomeArgs) msg.obj).arg1, (String[]) ((SomeArgs) msg.obj).arg2); break; + case EXECUTE_TRANSACTION: + ((ClientTransaction) msg.obj).execute(ActivityThread.this); + break; } Object obj = msg.obj; if (obj instanceof SomeArgs) { @@ -2601,10 +2330,16 @@ public final class ActivityThread { + " req=" + requestCode + " res=" + resultCode + " data=" + data); ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); list.add(new ResultInfo(id, requestCode, resultCode, data)); - mAppThread.scheduleSendResult(token, list); + final ClientTransaction clientTransaction = new ClientTransaction(mAppThread, token); + clientTransaction.addCallback(new ActivityResultItem(list)); + try { + mAppThread.scheduleTransaction(clientTransaction); + } catch (RemoteException e) { + // Local scheduling + } } - private void sendMessage(int what, Object obj) { + void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); } @@ -2844,6 +2579,37 @@ public final class ActivityThread { return appContext; } + @Override + public void handleLaunchActivity(IBinder token, Intent intent, int ident, ActivityInfo info, + Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, + IVoiceInteractor voiceInteractor, Bundle state, PersistableBundle persistentState, + List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, + boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { + ActivityClientRecord r = new ActivityClientRecord(); + + r.token = token; + r.ident = ident; + r.intent = intent; + r.referrer = referrer; + r.voiceInteractor = voiceInteractor; + r.activityInfo = info; + r.compatInfo = compatInfo; + r.state = state; + r.persistentState = persistentState; + + r.pendingResults = pendingResults; + r.pendingIntents = pendingNewIntents; + + r.startsNotResumed = notResumed; + r.isForward = isForward; + + r.profilerInfo = profilerInfo; + + r.overrideConfig = overrideConfig; + r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo); + handleLaunchActivity(r, null /* customIntent */, "LAUNCH_ACTIVITY"); + } + private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. @@ -2974,8 +2740,9 @@ public final class ActivityThread { } } - private void handleNewIntent(NewIntentData data) { - performNewIntents(data.token, data.intents, data.andPause); + @Override + public void handleNewIntent(IBinder token, List<ReferrerIntent> intents, boolean andPause) { + performNewIntents(token, intents, andPause); } public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) { @@ -3096,7 +2863,8 @@ public final class ActivityThread { } } - private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, + @Override + public void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, Configuration overrideConfig) { final ActivityClientRecord r = mActivities.get(token); if (r != null) { @@ -3108,7 +2876,8 @@ public final class ActivityThread { } } - private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, + @Override + public void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, Configuration overrideConfig) { final ActivityClientRecord r = mActivities.get(token); if (r != null) { @@ -3619,8 +3388,9 @@ public final class ActivityThread { r.mPendingRemoveWindowManager = null; } - final void handleResumeActivity(IBinder token, - boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { + @Override + public void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, + boolean reallyResume, int seq, String reason) { ActivityClientRecord r = mActivities.get(token); if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) { return; @@ -3823,7 +3593,8 @@ public final class ActivityThread { return thumbnail; } - private void handlePauseActivity(IBinder token, boolean finished, + @Override + public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport, int seq) { ActivityClientRecord r = mActivities.get(token); if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq); @@ -4087,7 +3858,8 @@ public final class ActivityThread { } } - private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) { + @Override + public void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) { ActivityClientRecord r = mActivities.get(token); if (!checkAndUpdateLifecycleSeq(seq, r, "stopActivity")) { return; @@ -4142,7 +3914,8 @@ public final class ActivityThread { } } - private void handleWindowVisibility(IBinder token, boolean show) { + @Override + public void handleWindowVisibility(IBinder token, boolean show) { ActivityClientRecord r = mActivities.get(token); if (r == null) { @@ -4288,8 +4061,9 @@ public final class ActivityThread { } } - private void handleSendResult(ResultData res) { - ActivityClientRecord r = mActivities.get(res.token); + @Override + public void handleSendResult(IBinder token, List<ResultInfo> results) { + ActivityClientRecord r = mActivities.get(token); if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r); if (r != null) { final boolean resumed = !r.paused; @@ -4323,7 +4097,7 @@ public final class ActivityThread { } } checkAndBlockForNetworkAccess(); - deliverResults(r, res.results); + deliverResults(r, results); if (resumed) { r.activity.performResume(); r.activity.mTemporaryPause = false; @@ -4410,8 +4184,9 @@ public final class ActivityThread { return component == null ? "[Unknown]" : component.toShortString(); } - private void handleDestroyActivity(IBinder token, boolean finishing, - int configChanges, boolean getNonConfigInstance) { + @Override + public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, + boolean getNonConfigInstance) { ActivityClientRecord r = performDestroyActivity(token, finishing, configChanges, getNonConfigInstance); if (r != null) { @@ -4982,7 +4757,20 @@ public final class ActivityThread { return config; } - final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) { + @Override + public void handleConfigurationChanged(Configuration config) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged"); + mCurDefaultDisplayDpi = config.densityDpi; + mUpdatingSystemConfig = true; + try { + handleConfigurationChanged(config, null /* compat */); + } finally { + mUpdatingSystemConfig = false; + } + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + + private void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) { int configDiff = 0; @@ -5113,12 +4901,15 @@ public final class ActivityThread { /** * Handle new activity configuration and/or move to a different display. - * @param data Configuration update data. + * @param activityToken Target activity token. + * @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. */ - void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) { - ActivityClientRecord r = mActivities.get(data.activityToken); + @Override + public void handleActivityConfigurationChanged(IBinder activityToken, + 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); @@ -5128,14 +4919,14 @@ public final class ActivityThread { && displayId != r.activity.getDisplay().getDisplayId(); // Perform updates. - r.overrideConfig = data.overrideConfig; + r.overrideConfig = overrideConfig; final ViewRootImpl viewRoot = r.activity.mDecor != null ? r.activity.mDecor.getViewRootImpl() : null; if (movedToDifferentDisplay) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:" + r.activityInfo.name + ", displayId=" + displayId - + ", config=" + data.overrideConfig); + + ", config=" + overrideConfig); final Configuration reportedConfig = performConfigurationChangedForActivity(r, mCompatConfiguration, displayId, true /* movedToDifferentDisplay */); @@ -5144,7 +4935,7 @@ public final class ActivityThread { } } else { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: " - + r.activityInfo.name + ", config=" + data.overrideConfig); + + r.activityInfo.name + ", config=" + overrideConfig); performConfigurationChangedForActivity(r, mCompatConfiguration); } // Notify the ViewRootImpl instance about configuration changes. It may have initiated this diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java new file mode 100644 index 000000000000..f7f4c716d0b7 --- /dev/null +++ b/core/java/android/app/ClientTransactionHandler.java @@ -0,0 +1,114 @@ +/* + * 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; + +import android.app.servertransaction.ClientTransaction; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.IBinder; +import android.os.PersistableBundle; + +import com.android.internal.app.IVoiceInteractor; +import com.android.internal.content.ReferrerIntent; + +import java.util.List; + +/** + * Defines operations that a {@link android.app.servertransaction.ClientTransaction} or its items + * can perform on client. + * @hide + */ +public abstract class ClientTransactionHandler { + + // Schedule phase related logic and handlers. + + /** Prepare and schedule transaction for execution. */ + void scheduleTransaction(ClientTransaction transaction) { + transaction.prepare(this); + sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); + } + + abstract void sendMessage(int what, Object obj); + + + // Prepare phase related logic and handlers. Methods that inform about about pending changes or + // do other internal bookkeeping. + + /** Get current lifecycle request number to maintain correct ordering. */ + public abstract int getLifecycleSeq(); + + /** Set pending config in case it will be updated by other transaction item. */ + public abstract void updatePendingConfiguration(Configuration config); + + /** Set current process state. */ + public abstract void updateProcessState(int processState, boolean fromIpc); + + + // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions + // and deliver callbacks. + + /** Destroy the activity. */ + public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, + boolean getNonConfigInstance); + + /** Pause the activity. */ + public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, + int configChanges, boolean dontReport, int seq); + + /** Resume the activity. */ + public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, + boolean reallyResume, int seq, String reason); + + /** Stop the activity. */ + public abstract void handleStopActivity(IBinder token, boolean show, int configChanges, + int seq); + + /** Deliver activity (override) configuration change. */ + public abstract void handleActivityConfigurationChanged(IBinder activityToken, + Configuration overrideConfig, int displayId); + + /** Deliver result from another activity. */ + public abstract void handleSendResult(IBinder token, List<ResultInfo> results); + + /** Deliver multi-window mode change notification. */ + public abstract void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, + Configuration overrideConfig); + + /** Deliver new intent. */ + public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents, + boolean andPause); + + /** Deliver picture-in-picture mode change notification. */ + public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode, + Configuration overrideConfig); + + /** Update window visibility. */ + public abstract void handleWindowVisibility(IBinder token, boolean show); + + /** Perform activity launch. */ + public abstract void handleLaunchActivity(IBinder token, Intent intent, int ident, + ActivityInfo info, Configuration overrideConfig, CompatibilityInfo compatInfo, + String referrer, IVoiceInteractor voiceInteractor, Bundle state, + PersistableBundle persistentState, List<ResultInfo> pendingResults, + List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, + ProfilerInfo profilerInfo); + + /** Deliver app configuration change notification. */ + public abstract void handleConfigurationChanged(Configuration config); +} diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 487a94a05f7a..b25d7782652f 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -20,6 +20,7 @@ import android.app.IInstrumentationWatcher; import android.app.IUiAutomationConnection; import android.app.ProfilerInfo; import android.app.ResultInfo; +import android.app.servertransaction.ClientTransaction; import android.content.ComponentName; import android.content.IIntentReceiver; import android.content.Intent; @@ -52,24 +53,6 @@ import java.util.Map; * {@hide} */ oneway interface IApplicationThread { - void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, - int configChanges, boolean dontReport); - void scheduleStopActivity(IBinder token, boolean showWindow, - int configChanges); - void scheduleWindowVisibility(IBinder token, boolean showWindow); - void scheduleResumeActivity(IBinder token, int procState, boolean isForward, - in Bundle resumeArgs); - void scheduleSendResult(IBinder token, in List<ResultInfo> results); - void scheduleLaunchActivity(in Intent intent, IBinder token, int ident, - in ActivityInfo info, in Configuration curConfig, in Configuration overrideConfig, - in CompatibilityInfo compatInfo, in String referrer, IVoiceInteractor voiceInteractor, - int procState, in Bundle state, in PersistableBundle persistentState, - in List<ResultInfo> pendingResults, in List<ReferrerIntent> pendingNewIntents, - boolean notResumed, boolean isForward, in ProfilerInfo profilerInfo); - void scheduleNewIntent( - in List<ReferrerIntent> intent, IBinder token, boolean andPause); - void scheduleDestroyActivity(IBinder token, boolean finished, - int configChanges); void scheduleReceiver(in Intent intent, in ActivityInfo info, in CompatibilityInfo compatInfo, int resultCode, in String data, in Bundle extras, boolean sync, @@ -87,7 +70,6 @@ oneway interface IApplicationThread { in Bundle coreSettings, in String buildSerial); void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs); void scheduleExit(); - void scheduleConfigurationChanged(in Configuration config); void scheduleServiceArgs(IBinder token, in ParceledListSlice args); void updateTimeZone(); void processInBackground(); @@ -101,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 scheduleActivityConfigurationChanged(IBinder token, in Configuration overrideConfig); - void scheduleActivityMovedToDisplay(IBinder token, int displayId, - in Configuration overrideConfig); void scheduleRelaunchActivity(IBinder token, in List<ResultInfo> pendingResults, in List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed, in Configuration config, in Configuration overrideConfig, boolean preserveWindow); @@ -146,14 +125,11 @@ oneway interface IApplicationThread { void notifyCleartextNetwork(in byte[] firstPacket); void startBinderTracking(); void stopBinderTrackingAndDump(in ParcelFileDescriptor fd); - void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode, - in Configuration newConfig); - void schedulePictureInPictureModeChanged(IBinder token, boolean isInPictureInPictureMode, - in Configuration newConfig); void scheduleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor voiceInteractor); void handleTrustStorageUpdate(); void attachAgent(String path); void scheduleApplicationInfoChanged(in ApplicationInfo ai); void setNetworkBlockSeq(long procStateSeq); + void scheduleTransaction(in ClientTransaction transaction); } diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java new file mode 100644 index 000000000000..fc4f431d9947 --- /dev/null +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -0,0 +1,71 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import static android.view.Display.INVALID_DISPLAY; + +import android.content.res.Configuration; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; + +/** + * Activity configuration changed callback. + * @hide + */ +public class ActivityConfigurationChangeItem extends ClientTransactionItem { + + private final Configuration mConfiguration; + + public ActivityConfigurationChangeItem(Configuration configuration) { + mConfiguration = configuration; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + // 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); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedObject(mConfiguration, flags); + } + + /** Read from Parcel. */ + private ActivityConfigurationChangeItem(Parcel in) { + mConfiguration = in.readTypedObject(Configuration.CREATOR); + } + + public static final Creator<ActivityConfigurationChangeItem> CREATOR = + new Creator<ActivityConfigurationChangeItem>() { + public ActivityConfigurationChangeItem createFromParcel(Parcel in) { + return new ActivityConfigurationChangeItem(in); + } + + public ActivityConfigurationChangeItem[] newArray(int size) { + return new ActivityConfigurationChangeItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java new file mode 100644 index 000000000000..a64108db7c21 --- /dev/null +++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java @@ -0,0 +1,44 @@ +/* + * 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 android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Request for lifecycle state that an activity should reach. + * @hide + */ +public abstract class ActivityLifecycleItem extends ClientTransactionItem { + + static final boolean DEBUG_ORDER = false; + + @IntDef({UNDEFINED, RESUMED, PAUSED, STOPPED, DESTROYED}) + @Retention(RetentionPolicy.SOURCE) + @interface LifecycleState{} + public static final int UNDEFINED = -1; + public static final int RESUMED = 0; + public static final int PAUSED = 1; + public static final int STOPPED = 2; + public static final int DESTROYED = 3; + + /** A final lifecycle state that an activity should reach. */ + @LifecycleState + public abstract int getTargetState(); +} diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java new file mode 100644 index 000000000000..d77f767056b7 --- /dev/null +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -0,0 +1,78 @@ +/* + * 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.servertransaction.ActivityLifecycleItem.PAUSED; +import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.app.ResultInfo; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Trace; + +import java.util.List; + +/** + * Activity result delivery callback. + * @hide + */ +public class ActivityResultItem extends ClientTransactionItem { + + private final List<ResultInfo> mResultInfoList; + + public ActivityResultItem(List<ResultInfo> resultInfos) { + mResultInfoList = resultInfos; + } + + @Override + public int getPreExecutionState() { + return PAUSED; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult"); + client.handleSendResult(token, mResultInfoList); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedList(mResultInfoList, flags); + } + + /** Read from Parcel. */ + private ActivityResultItem(Parcel in) { + mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR); + } + + public static final Parcelable.Creator<ActivityResultItem> CREATOR = + new Parcelable.Creator<ActivityResultItem>() { + public ActivityResultItem createFromParcel(Parcel in) { + return new ActivityResultItem(in); + } + + public ActivityResultItem[] newArray(int size) { + return new ActivityResultItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/BaseClientRequest.java b/core/java/android/app/servertransaction/BaseClientRequest.java new file mode 100644 index 000000000000..4bd01afb5061 --- /dev/null +++ b/core/java/android/app/servertransaction/BaseClientRequest.java @@ -0,0 +1,45 @@ +/* + * 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 android.app.ClientTransactionHandler; +import android.os.IBinder; + +/** + * Base interface for individual requests from server to client. + * Each of them can be prepared before scheduling and, eventually, executed. + * @hide + */ +public interface BaseClientRequest { + + /** + * Prepare the client request before scheduling. + * An example of this might be informing about pending updates for some values. + * + * @param client Target client handler. + * @param token Target activity token. + */ + default void prepare(ClientTransactionHandler client, IBinder token) { + } + + /** + * Execute the request. + * @param client Target client handler. + * @param token Target activity token. + */ + void execute(ClientTransactionHandler client, IBinder token); +} diff --git a/core/java/android/app/servertransaction/ClientTransaction.aidl b/core/java/android/app/servertransaction/ClientTransaction.aidl new file mode 100644 index 000000000000..ad8bcbf6eb04 --- /dev/null +++ b/core/java/android/app/servertransaction/ClientTransaction.aidl @@ -0,0 +1,20 @@ +/* + * 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; + +/** @hide */ +parcelable ClientTransaction;
\ No newline at end of file diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java new file mode 100644 index 000000000000..211a3fd4ba15 --- /dev/null +++ b/core/java/android/app/servertransaction/ClientTransaction.java @@ -0,0 +1,175 @@ +/* + * 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 android.app.IApplicationThread; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; + +import java.util.ArrayList; +import java.util.List; + +/** + * A container that holds a sequence of messages, which may be sent to a client. + * This includes a list of callbacks and a final lifecycle state. + * + * @see com.android.server.am.ClientLifecycleManager + * @see ClientTransactionItem + * @see ActivityLifecycleItem + * @hide + */ +public class ClientTransaction implements Parcelable { + + /** A list of individual callbacks to a client. */ + private List<ClientTransactionItem> mActivityCallbacks; + + /** + * Final lifecycle state in which the client activity should be after the transaction is + * executed. + */ + private ActivityLifecycleItem mLifecycleStateRequest; + + /** Target client. */ + private IApplicationThread mClient; + + /** Target client activity. Might be null if the entire transaction is targeting an app. */ + private IBinder mActivityToken; + + public ClientTransaction(IApplicationThread client, IBinder activityToken) { + mClient = client; + mActivityToken = activityToken; + } + + /** + * Add a message to the end of the sequence of callbacks. + * @param activityCallback A single message that can contain a lifecycle request/callback. + */ + public void addCallback(ClientTransactionItem activityCallback) { + if (mActivityCallbacks == null) { + mActivityCallbacks = new ArrayList<>(); + } + mActivityCallbacks.add(activityCallback); + } + + /** + * Set the lifecycle state in which the client should be after executing the transaction. + * @param stateRequest A lifecycle request initialized with right parameters. + */ + public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) { + mLifecycleStateRequest = stateRequest; + } + + /** + * Do what needs to be done while the transaction is being scheduled on the client side. + * @param clientTransactionHandler Handler on the client side that will executed all operations + * requested by transaction items. + */ + public void prepare(android.app.ClientTransactionHandler clientTransactionHandler) { + if (mActivityCallbacks != null) { + final int size = mActivityCallbacks.size(); + for (int i = 0; i < size; ++i) { + mActivityCallbacks.get(i).prepare(clientTransactionHandler, mActivityToken); + } + } + if (mLifecycleStateRequest != null) { + mLifecycleStateRequest.prepare(clientTransactionHandler, mActivityToken); + } + } + + /** + * Execute the transaction. + * @param clientTransactionHandler Handler on the client side that will execute all operations + * requested by transaction items. + */ + public void execute(android.app.ClientTransactionHandler clientTransactionHandler) { + if (mActivityCallbacks != null) { + final int size = mActivityCallbacks.size(); + for (int i = 0; i < size; ++i) { + mActivityCallbacks.get(i).execute(clientTransactionHandler, mActivityToken); + } + } + if (mLifecycleStateRequest != null) { + mLifecycleStateRequest.execute(clientTransactionHandler, mActivityToken); + } + } + + /** + * Schedule the transaction after it was initialized. It will be send to client and all its + * individual parts will be applied in the following sequence: + * 1. The client calls {@link #prepare()}, which triggers all work that needs to be done before + * actually scheduling the transaction for callbacks and lifecycle state request. + * 2. The transaction message is scheduled. + * 3. The client calls {@link #execute()}, which executes all callbacks and necessary lifecycle + * transitions. + */ + public void schedule() throws RemoteException { + mClient.scheduleTransaction(this); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongBinder(mClient.asBinder()); + final boolean writeActivityToken = mActivityToken != null; + dest.writeBoolean(writeActivityToken); + if (writeActivityToken) { + dest.writeStrongBinder(mActivityToken); + } + dest.writeParcelable(mLifecycleStateRequest, flags); + final boolean writeActivityCallbacks = mActivityCallbacks != null; + dest.writeBoolean(writeActivityCallbacks); + if (writeActivityCallbacks) { + dest.writeParcelableList(mActivityCallbacks, flags); + } + } + + /** Read from Parcel. */ + private ClientTransaction(Parcel in) { + mClient = (IApplicationThread) in.readStrongBinder(); + final boolean readActivityToken = in.readBoolean(); + if (readActivityToken) { + mActivityToken = in.readStrongBinder(); + } + mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader()); + final boolean readActivityCallbacks = in.readBoolean(); + if (readActivityCallbacks) { + mActivityCallbacks = new ArrayList<>(); + in.readParcelableList(mActivityCallbacks, getClass().getClassLoader()); + } + } + + public static final Creator<ClientTransaction> CREATOR = + new Creator<ClientTransaction>() { + public ClientTransaction createFromParcel(Parcel in) { + return new ClientTransaction(in); + } + + public ClientTransaction[] newArray(int size) { + return new ClientTransaction[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java new file mode 100644 index 000000000000..6f2cc007ac27 --- /dev/null +++ b/core/java/android/app/servertransaction/ClientTransactionItem.java @@ -0,0 +1,54 @@ +/* + * 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.servertransaction.ActivityLifecycleItem.LifecycleState; +import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; + +import android.os.Parcelable; + +/** + * A callback message to a client that can be scheduled and executed. + * Examples of these might be activity configuration change, multi-window mode change, activity + * result delivery etc. + * + * @see ClientTransaction + * @see com.android.server.am.ClientLifecycleManager + * @hide + */ +public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable { + + /** Get the state in which this callback can be executed. */ + @LifecycleState + public int getPreExecutionState() { + return UNDEFINED; + } + + /** Get the state that must follow this callback. */ + @LifecycleState + public int getPostExecutionState() { + return UNDEFINED; + } + + + // Parcelable + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/app/servertransaction/ConfigurationChangeItem.java b/core/java/android/app/servertransaction/ConfigurationChangeItem.java new file mode 100644 index 000000000000..2f128e597e2d --- /dev/null +++ b/core/java/android/app/servertransaction/ConfigurationChangeItem.java @@ -0,0 +1,68 @@ +/* + * 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 android.content.res.Configuration; +import android.os.IBinder; +import android.os.Parcel; + +/** + * App configuration change message. + * @hide + */ +public class ConfigurationChangeItem extends ClientTransactionItem { + + private final Configuration mConfiguration; + + public ConfigurationChangeItem(Configuration configuration) { + mConfiguration = new Configuration(configuration); + } + + @Override + public void prepare(android.app.ClientTransactionHandler client, IBinder token) { + client.updatePendingConfiguration(mConfiguration); + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + client.handleConfigurationChanged(mConfiguration); + } + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedObject(mConfiguration, flags); + } + + /** Read from Parcel. */ + private ConfigurationChangeItem(Parcel in) { + mConfiguration = in.readTypedObject(Configuration.CREATOR); + } + + public static final Creator<ConfigurationChangeItem> CREATOR = + new Creator<ConfigurationChangeItem>() { + public ConfigurationChangeItem createFromParcel(Parcel in) { + return new ConfigurationChangeItem(in); + } + + public ConfigurationChangeItem[] newArray(int size) { + return new ConfigurationChangeItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java new file mode 100644 index 000000000000..3a61dfe670f2 --- /dev/null +++ b/core/java/android/app/servertransaction/DestroyActivityItem.java @@ -0,0 +1,79 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.app.ClientTransactionHandler; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; + +/** + * Request to destroy an activity. + * @hide + */ +public class DestroyActivityItem extends ActivityLifecycleItem { + + private final boolean mFinished; + private final int mConfigChanges; + + public DestroyActivityItem(boolean finished, int configChanges) { + mFinished = finished; + mConfigChanges = configChanges; + } + + @Override + public void execute(ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); + client.handleDestroyActivity(token, mFinished, mConfigChanges, + false /* getNonConfigInstance */); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + @Override + public int getTargetState() { + return DESTROYED; + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mFinished); + dest.writeInt(mConfigChanges); + } + + /** Read from Parcel. */ + private DestroyActivityItem(Parcel in) { + mFinished = in.readBoolean(); + mConfigChanges = in.readInt(); + } + + public static final Creator<DestroyActivityItem> CREATOR = + new Creator<DestroyActivityItem>() { + public DestroyActivityItem createFromParcel(Parcel in) { + return new DestroyActivityItem(in); + } + + public DestroyActivityItem[] newArray(int size) { + return new DestroyActivityItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java new file mode 100644 index 000000000000..d945a5fd5155 --- /dev/null +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -0,0 +1,161 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.app.ClientTransactionHandler; +import android.app.ProfilerInfo; +import android.app.ResultInfo; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Parcel; +import android.os.PersistableBundle; +import android.os.Trace; + +import com.android.internal.app.IVoiceInteractor; +import com.android.internal.content.ReferrerIntent; + +import java.util.List; + +/** + * Request to launch an activity. + * @hide + */ +public class LaunchActivityItem extends ActivityLifecycleItem { + + private final Intent mIntent; + private final int mIdent; + private final ActivityInfo mInfo; + private final Configuration mCurConfig; + private final Configuration mOverrideConfig; + private final CompatibilityInfo mCompatInfo; + private final String mReferrer; + private final IVoiceInteractor mVoiceInteractor; + private final int mProcState; + private final Bundle mState; + private final PersistableBundle mPersistentState; + private final List<ResultInfo> mPendingResults; + private final List<ReferrerIntent> mPendingNewIntents; + // TODO(lifecycler): use lifecycle request instead of this param. + private final boolean mNotResumed; + private final boolean mIsForward; + private final ProfilerInfo mProfilerInfo; + + public LaunchActivityItem(Intent intent, int ident, ActivityInfo info, + Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, + String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, + PersistableBundle persistentState, List<ResultInfo> pendingResults, + List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, + ProfilerInfo profilerInfo) { + mIntent = intent; + mIdent = ident; + mInfo = info; + mCurConfig = curConfig; + mOverrideConfig = overrideConfig; + mCompatInfo = compatInfo; + mReferrer = referrer; + mVoiceInteractor = voiceInteractor; + mProcState = procState; + mState = state; + mPersistentState = persistentState; + mPendingResults = pendingResults; + mPendingNewIntents = pendingNewIntents; + mNotResumed = notResumed; + mIsForward = isForward; + mProfilerInfo = profilerInfo; + } + + @Override + public void prepare(ClientTransactionHandler client, IBinder token) { + client.updateProcessState(mProcState, false); + client.updatePendingConfiguration(mCurConfig); + } + + @Override + public void execute(ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); + client.handleLaunchActivity(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo, + mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, + mPendingNewIntents, mNotResumed, mIsForward, mProfilerInfo); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + @Override + public int getTargetState() { + return mNotResumed ? PAUSED : RESUMED; + } + + + // Parcelable implementation + + /** Write from Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedObject(mIntent, flags); + dest.writeInt(mIdent); + dest.writeTypedObject(mInfo, flags); + dest.writeTypedObject(mCurConfig, flags); + dest.writeTypedObject(mOverrideConfig, flags); + dest.writeTypedObject(mCompatInfo, flags); + dest.writeString(mReferrer); + dest.writeStrongBinder(mVoiceInteractor != null ? mVoiceInteractor.asBinder() : null); + dest.writeInt(mProcState); + dest.writeBundle(mState); + dest.writePersistableBundle(mPersistentState); + dest.writeTypedList(mPendingResults, flags); + dest.writeTypedList(mPendingNewIntents, flags); + dest.writeBoolean(mNotResumed); + dest.writeBoolean(mIsForward); + dest.writeTypedObject(mProfilerInfo, flags); + } + + /** Read from Parcel. */ + private LaunchActivityItem(Parcel in) { + mIntent = in.readTypedObject(Intent.CREATOR); + mIdent = in.readInt(); + mInfo = in.readTypedObject(ActivityInfo.CREATOR); + mCurConfig = in.readTypedObject(Configuration.CREATOR); + mOverrideConfig = in.readTypedObject(Configuration.CREATOR); + mCompatInfo = in.readTypedObject(CompatibilityInfo.CREATOR); + mReferrer = in.readString(); + mVoiceInteractor = (IVoiceInteractor) in.readStrongBinder(); + mProcState = in.readInt(); + mState = in.readBundle(getClass().getClassLoader()); + mPersistentState = in.readPersistableBundle(getClass().getClassLoader()); + mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR); + mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); + mNotResumed = in.readBoolean(); + mIsForward = in.readBoolean(); + mProfilerInfo = in.readTypedObject(ProfilerInfo.CREATOR); + } + + public static final Creator<LaunchActivityItem> CREATOR = + new Creator<LaunchActivityItem>() { + public LaunchActivityItem createFromParcel(Parcel in) { + return new LaunchActivityItem(in); + } + + public LaunchActivityItem[] newArray(int size) { + return new LaunchActivityItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java new file mode 100644 index 000000000000..93ce78d9a323 --- /dev/null +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -0,0 +1,73 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.content.res.Configuration; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; + +/** + * Activity move to a different display message. + * @hide + */ +public class MoveToDisplayItem extends ClientTransactionItem { + + private final int mTargetDisplayId; + private final Configuration mConfiguration; + + public MoveToDisplayItem(int targetDisplayId, Configuration configuration) { + mTargetDisplayId = targetDisplayId; + mConfiguration = configuration; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay"); + client.handleActivityConfigurationChanged(token, mConfiguration, mTargetDisplayId); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mTargetDisplayId); + dest.writeTypedObject(mConfiguration, flags); + } + + /** Read from Parcel. */ + private MoveToDisplayItem(Parcel in) { + mTargetDisplayId = in.readInt(); + mConfiguration = in.readTypedObject(Configuration.CREATOR); + } + + public static final Creator<MoveToDisplayItem> CREATOR = + new Creator<MoveToDisplayItem>() { + public MoveToDisplayItem createFromParcel(Parcel in) { + return new MoveToDisplayItem(in); + } + + public MoveToDisplayItem[] newArray(int size) { + return new MoveToDisplayItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java new file mode 100644 index 000000000000..7f83d477104b --- /dev/null +++ b/core/java/android/app/servertransaction/MultiWindowModeChangeItem.java @@ -0,0 +1,71 @@ +/* + * 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 android.content.res.Configuration; +import android.os.IBinder; +import android.os.Parcel; + +/** + * Multi-window mode change message. + * @hide + */ +// TODO(lifecycler): Remove the use of this and just use the configuration change message to +// communicate multi-window mode change with WindowConfiguration. +public class MultiWindowModeChangeItem extends ClientTransactionItem { + + private final boolean mIsInMultiWindowMode; + private final Configuration mOverrideConfig; + + public MultiWindowModeChangeItem(boolean isInMultiWindowMode, + Configuration overrideConfig) { + mIsInMultiWindowMode = isInMultiWindowMode; + mOverrideConfig = overrideConfig; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + client.handleMultiWindowModeChanged(token, mIsInMultiWindowMode, mOverrideConfig); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mIsInMultiWindowMode); + dest.writeTypedObject(mOverrideConfig, flags); + } + + /** Read from Parcel. */ + private MultiWindowModeChangeItem(Parcel in) { + mIsInMultiWindowMode = in.readBoolean(); + mOverrideConfig = in.readTypedObject(Configuration.CREATOR); + } + + public static final Creator<MultiWindowModeChangeItem> CREATOR = + new Creator<MultiWindowModeChangeItem>() { + public MultiWindowModeChangeItem createFromParcel(Parcel in) { + return new MultiWindowModeChangeItem(in); + } + + public MultiWindowModeChangeItem[] newArray(int size) { + return new MultiWindowModeChangeItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java new file mode 100644 index 000000000000..32b11f7f92c8 --- /dev/null +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -0,0 +1,88 @@ +/* + * 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.servertransaction.ActivityLifecycleItem.PAUSED; +import static android.app.servertransaction.ActivityLifecycleItem.RESUMED; + +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Trace; + +import com.android.internal.content.ReferrerIntent; + +import java.util.List; + +/** + * New intent message. + * @hide + */ +public class NewIntentItem extends ClientTransactionItem { + + private final List<ReferrerIntent> mIntents; + private final boolean mPause; + + public NewIntentItem(List<ReferrerIntent> intents, boolean pause) { + mIntents = intents; + mPause = pause; + } + + @Override + public int getPreExecutionState() { + return PAUSED; + } + + @Override + public int getPostExecutionState() { + return RESUMED; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); + client.handleNewIntent(token, mIntents, mPause); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mPause); + dest.writeTypedList(mIntents, flags); + } + + /** Read from Parcel. */ + private NewIntentItem(Parcel in) { + mPause = in.readBoolean(); + mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); + } + + public static final Parcelable.Creator<NewIntentItem> CREATOR = + new Parcelable.Creator<NewIntentItem>() { + public NewIntentItem createFromParcel(Parcel in) { + return new NewIntentItem(in); + } + + public NewIntentItem[] newArray(int size) { + return new NewIntentItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java new file mode 100644 index 000000000000..6f2c60d25d57 --- /dev/null +++ b/core/java/android/app/servertransaction/PauseActivityItem.java @@ -0,0 +1,102 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.app.ClientTransactionHandler; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; +import android.util.Slog; + +/** + * Request to move an activity to paused state. + * @hide + */ +public class PauseActivityItem extends ActivityLifecycleItem { + + private static final String TAG = "PauseActivityItem"; + + private final boolean mFinished; + private final boolean mUserLeaving; + private final int mConfigChanges; + private final boolean mDontReport; + + private int mLifecycleSeq; + + public PauseActivityItem(boolean finished, boolean userLeaving, int configChanges, + boolean dontReport) { + mFinished = finished; + mUserLeaving = userLeaving; + mConfigChanges = configChanges; + mDontReport = dontReport; + } + + @Override + public void prepare(ClientTransactionHandler client, IBinder token) { + mLifecycleSeq = client.getLifecycleSeq(); + if (DEBUG_ORDER) { + Slog.d(TAG, "Pause transaction for " + client + " received seq: " + + mLifecycleSeq); + } + } + + @Override + public void execute(ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); + client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, mDontReport, + mLifecycleSeq); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + @Override + public int getTargetState() { + return PAUSED; + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mFinished); + dest.writeBoolean(mUserLeaving); + dest.writeInt(mConfigChanges); + dest.writeBoolean(mDontReport); + } + + /** Read from Parcel. */ + private PauseActivityItem(Parcel in) { + mFinished = in.readBoolean(); + mUserLeaving = in.readBoolean(); + mConfigChanges = in.readInt(); + mDontReport = in.readBoolean(); + } + + public static final Creator<PauseActivityItem> CREATOR = + new Creator<PauseActivityItem>() { + public PauseActivityItem createFromParcel(Parcel in) { + return new PauseActivityItem(in); + } + + public PauseActivityItem[] newArray(int size) { + return new PauseActivityItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/PipModeChangeItem.java b/core/java/android/app/servertransaction/PipModeChangeItem.java new file mode 100644 index 000000000000..1e713b6070c0 --- /dev/null +++ b/core/java/android/app/servertransaction/PipModeChangeItem.java @@ -0,0 +1,69 @@ +/* + * 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 android.content.res.Configuration; +import android.os.IBinder; +import android.os.Parcel; + +/** + * Picture in picture mode change message. + * @hide + */ +// TODO(lifecycler): Remove the use of this and just use the configuration change message to +// communicate multi-window mode change with WindowConfiguration. +public class PipModeChangeItem extends ClientTransactionItem { + + private final boolean mIsInPipMode; + private final Configuration mOverrideConfig; + + public PipModeChangeItem(boolean isInPipMode, Configuration overrideConfig) { + mIsInPipMode = isInPipMode; + mOverrideConfig = overrideConfig; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + client.handlePictureInPictureModeChanged(token, mIsInPipMode, mOverrideConfig); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mIsInPipMode); + dest.writeTypedObject(mOverrideConfig, flags); + } + + /** Read from Parcel. */ + private PipModeChangeItem(Parcel in) { + mIsInPipMode = in.readBoolean(); + mOverrideConfig = in.readTypedObject(Configuration.CREATOR); + } + + public static final Creator<PipModeChangeItem> CREATOR = + new Creator<PipModeChangeItem>() { + public PipModeChangeItem createFromParcel(Parcel in) { + return new PipModeChangeItem(in); + } + + public PipModeChangeItem[] newArray(int size) { + return new PipModeChangeItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java new file mode 100644 index 000000000000..bf6b6e2c220e --- /dev/null +++ b/core/java/android/app/servertransaction/ResumeActivityItem.java @@ -0,0 +1,94 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.app.ClientTransactionHandler; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; +import android.util.Slog; + +/** + * Request to move an activity to resumed state. + * @hide + */ +public class ResumeActivityItem extends ActivityLifecycleItem { + + private static final String TAG = "ResumeActivityItem"; + + private final int mProcState; + private final boolean mIsForward; + + private int mLifecycleSeq; + + public ResumeActivityItem(int procState, boolean isForward) { + mProcState = procState; + mIsForward = isForward; + } + + @Override + public void prepare(ClientTransactionHandler client, IBinder token) { + mLifecycleSeq = client.getLifecycleSeq(); + if (DEBUG_ORDER) { + Slog.d(TAG, "Resume transaction for " + client + " received seq: " + + mLifecycleSeq); + } + client.updateProcessState(mProcState, false); + } + + @Override + public void execute(ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); + client.handleResumeActivity(token, true /* clearHide */, mIsForward, + true /* reallyResume */, mLifecycleSeq, "RESUME_ACTIVITY"); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + @Override + public int getTargetState() { + return RESUMED; + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mProcState); + dest.writeBoolean(mIsForward); + } + + /** Read from Parcel. */ + private ResumeActivityItem(Parcel in) { + mProcState = in.readInt(); + mIsForward = in.readBoolean(); + } + + public static final Creator<ResumeActivityItem> CREATOR = + new Creator<ResumeActivityItem>() { + public ResumeActivityItem createFromParcel(Parcel in) { + return new ResumeActivityItem(in); + } + + public ResumeActivityItem[] newArray(int size) { + return new ResumeActivityItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java new file mode 100644 index 000000000000..36123c67e3ba --- /dev/null +++ b/core/java/android/app/servertransaction/StopActivityItem.java @@ -0,0 +1,92 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.app.ClientTransactionHandler; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; +import android.util.Slog; + +/** + * Request to move an activity to stopped state. + * @hide + */ +public class StopActivityItem extends ActivityLifecycleItem { + + private static final String TAG = "StopActivityItem"; + + private final boolean mShowWindow; + private final int mConfigChanges; + + private int mLifecycleSeq; + + public StopActivityItem(boolean showWindow, int configChanges) { + mShowWindow = showWindow; + mConfigChanges = configChanges; + } + + @Override + public void prepare(ClientTransactionHandler client, IBinder token) { + mLifecycleSeq = client.getLifecycleSeq(); + if (DEBUG_ORDER) { + Slog.d(TAG, "Stop transaction for " + client + " received seq: " + + mLifecycleSeq); + } + } + + @Override + public void execute(ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); + client.handleStopActivity(token, mShowWindow, mConfigChanges, mLifecycleSeq); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + @Override + public int getTargetState() { + return STOPPED; + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mShowWindow); + dest.writeInt(mConfigChanges); + } + + /** Read from Parcel. */ + private StopActivityItem(Parcel in) { + mShowWindow = in.readBoolean(); + mConfigChanges = in.readInt(); + } + + public static final Creator<StopActivityItem> CREATOR = + new Creator<StopActivityItem>() { + public StopActivityItem createFromParcel(Parcel in) { + return new StopActivityItem(in); + } + + public StopActivityItem[] newArray(int size) { + return new StopActivityItem[size]; + } + }; +} diff --git a/core/java/android/app/servertransaction/WindowVisibilityItem.java b/core/java/android/app/servertransaction/WindowVisibilityItem.java new file mode 100644 index 000000000000..28308c30dcba --- /dev/null +++ b/core/java/android/app/servertransaction/WindowVisibilityItem.java @@ -0,0 +1,68 @@ +/* + * 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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; + +import android.os.IBinder; +import android.os.Parcel; +import android.os.Trace; + +/** + * Window visibility change message. + * @hide + */ +public class WindowVisibilityItem extends ClientTransactionItem { + + private final boolean mShowWindow; + + public WindowVisibilityItem(boolean showWindow) { + mShowWindow = showWindow; + } + + @Override + public void execute(android.app.ClientTransactionHandler client, IBinder token) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow"); + client.handleWindowVisibility(token, mShowWindow); + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + + + // Parcelable implementation + + /** Write to Parcel. */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mShowWindow); + } + + /** Read from Parcel. */ + private WindowVisibilityItem(Parcel in) { + mShowWindow = in.readBoolean(); + } + + public static final Creator<WindowVisibilityItem> CREATOR = + new Creator<WindowVisibilityItem>() { + public WindowVisibilityItem createFromParcel(Parcel in) { + return new WindowVisibilityItem(in); + } + + public WindowVisibilityItem[] newArray(int size) { + return new WindowVisibilityItem[size]; + } + }; +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 86ef8572dad3..bbd04d6a2bc4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -245,6 +245,7 @@ import android.app.admin.DevicePolicyManager; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.IBackupManager; +import android.app.servertransaction.ConfigurationChangeItem; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; @@ -630,6 +631,8 @@ public class ActivityManagerService extends IActivityManager.Stub final ActivityStarter mActivityStarter; + final ClientLifecycleManager mLifecycleManager; + final TaskChangeNotificationController mTaskChangeNotificationController; final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter(); @@ -2689,6 +2692,7 @@ public class ActivityManagerService extends IActivityManager.Stub mUserController = null; mVrController = null; mLockTaskController = null; + mLifecycleManager = null; } // Note: This method is invoked on the main thread but may need to attach various @@ -2788,6 +2792,7 @@ public class ActivityManagerService extends IActivityManager.Stub mRecentTasks = createRecentTasks(); mStackSupervisor.setRecentTasks(mRecentTasks); mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler); + mLifecycleManager = new ClientLifecycleManager(); mProcessCpuThread = new Thread("CpuTracker") { @Override @@ -20450,9 +20455,11 @@ public class ActivityManagerService extends IActivityManager.Stub if (app.thread != null) { if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc " + app.processName + " new config " + configCopy); - app.thread.scheduleConfigurationChanged(configCopy); + mLifecycleManager.scheduleTransaction(app.thread, + new ConfigurationChangeItem(configCopy)); } } catch (Exception e) { + Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index b2308d5ec9af..4de1a960e700 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -131,6 +131,12 @@ import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.PictureInPictureParams; import android.app.ResultInfo; +import android.app.servertransaction.MoveToDisplayItem; +import android.app.servertransaction.MultiWindowModeChangeItem; +import android.app.servertransaction.NewIntentItem; +import android.app.servertransaction.PipModeChangeItem; +import android.app.servertransaction.WindowVisibilityItem; +import android.app.servertransaction.ActivityConfigurationChangeItem; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -618,8 +624,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo "Reporting activity moved to display" + ", activityRecord=" + this + ", displayId=" + displayId + ", config=" + config); - app.thread.scheduleActivityMovedToDisplay(appToken, displayId, - new Configuration(config)); + service.mLifecycleManager.scheduleTransaction(app.thread, appToken, + new MoveToDisplayItem(displayId, config)); } catch (RemoteException e) { // If process died, whatever. } @@ -636,7 +642,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: " + config); - app.thread.scheduleActivityConfigurationChanged(appToken, new Configuration(config)); + service.mLifecycleManager.scheduleTransaction(app.thread, appToken, + new ActivityConfigurationChangeItem(config)); } catch (RemoteException e) { // If process died, whatever. } @@ -657,8 +664,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo private void scheduleMultiWindowModeChanged(Configuration overrideConfig) { try { - app.thread.scheduleMultiWindowModeChanged(appToken, mLastReportedMultiWindowMode, - overrideConfig); + service.mLifecycleManager.scheduleTransaction(app.thread, appToken, + new MultiWindowModeChangeItem(mLastReportedMultiWindowMode, + overrideConfig)); } catch (Exception e) { // If process died, I don't care. } @@ -684,8 +692,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo private void schedulePictureInPictureModeChanged(Configuration overrideConfig) { try { - app.thread.schedulePictureInPictureModeChanged(appToken, - mLastReportedPictureInPictureMode, overrideConfig); + service.mLifecycleManager.scheduleTransaction(app.thread, appToken, + new PipModeChangeItem(mLastReportedPictureInPictureMode, + overrideConfig)); } catch (Exception e) { // If process died, no one cares. } @@ -1364,8 +1373,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo try { ArrayList<ReferrerIntent> ar = new ArrayList<>(1); ar.add(rintent); - app.thread.scheduleNewIntent( - ar, appToken, state == PAUSED /* andPause */); + service.mLifecycleManager.scheduleTransaction(app.thread, appToken, + new NewIntentItem(ar, state == PAUSED)); unsent = false; } catch (RemoteException e) { Slog.w(TAG, "Exception thrown sending new intent to " + this, e); @@ -1587,7 +1596,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo setVisible(true); sleeping = false; app.pendingUiClean = true; - app.thread.scheduleWindowVisibility(appToken, true /* showWindow */); + service.mLifecycleManager.scheduleTransaction(app.thread, appToken, + new WindowVisibilityItem(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); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 8cc584e44d19..76f9870a5374 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -95,13 +95,19 @@ import static java.lang.Integer.MAX_VALUE; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityController; import android.app.ResultInfo; import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; +import android.app.servertransaction.ActivityResultItem; +import android.app.servertransaction.NewIntentItem; +import android.app.servertransaction.WindowVisibilityItem; +import android.app.servertransaction.DestroyActivityItem; +import android.app.servertransaction.PauseActivityItem; +import android.app.servertransaction.ResumeActivityItem; +import android.app.servertransaction.StopActivityItem; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -1315,8 +1321,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai prev.userId, System.identityHashCode(prev), prev.shortComponentName); mService.updateUsageStats(prev, false); - prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, - userLeaving, prev.configChangeFlags, pauseImmediately); + + mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken, + new PauseActivityItem(prev.finishing, userLeaving, + prev.configChangeFlags, pauseImmediately)); } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Slog.w(TAG, "Exception thrown during pause", e); @@ -1946,7 +1954,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (r.app != null && r.app.thread != null) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Scheduling invisibility: " + r); - r.app.thread.scheduleWindowVisibility(r.appToken, false); + mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken, + new WindowVisibilityItem(false /* showWindow */)); } // Reset the flag indicating that an app can enter picture-in-picture once the @@ -2466,13 +2475,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (!next.finishing && N > 0) { if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a); - next.app.thread.scheduleSendResult(next.appToken, a); + mService.mLifecycleManager.scheduleTransaction(next.app.thread, + next.appToken, new ActivityResultItem(a)); } } if (next.newIntents != null) { - next.app.thread.scheduleNewIntent( - next.newIntents, next.appToken, false /* andPause */); + mService.mLifecycleManager.scheduleTransaction(next.app.thread, + next.appToken, new NewIntentItem(next.newIntents, + false /* andPause */)); } // Well the app will no longer be stopped. @@ -2489,8 +2500,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai next.app.pendingUiClean = true; next.app.forceProcessStateUpTo(mService.mTopProcessState); next.clearOptionsLocked(); - next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState, - mService.isNextTransitionForward(), resumeAnimOptions); + mService.mLifecycleManager.scheduleTransaction(next.app.thread, next.appToken, + new ResumeActivityItem(next.app.repProcState, + mService.isNextTransitionForward())); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next); @@ -3141,7 +3153,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); list.add(new ResultInfo(resultWho, requestCode, resultCode, data)); - r.app.thread.scheduleSendResult(r.appToken, list); + mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken, + new ActivityResultItem(list)); return; } catch (Exception e) { Slog.w(TAG, "Exception thrown sending result to " + r, e); @@ -3269,7 +3282,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } EventLogTags.writeAmStopActivity( r.userId, System.identityHashCode(r), r.shortComponentName); - r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags); + mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken, + new StopActivityItem(r.visible, r.configChangeFlags)); if (shouldSleepOrShutDownActivities()) { r.setSleeping(true); } @@ -4066,8 +4080,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai try { if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r); - r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing, - r.configChangeFlags); + mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken, + new DestroyActivityItem(r.finishing, r.configChangeFlags)); } catch (Exception e) { // We can just ignore exceptions here... if the process // has crashed, our death notification will clean things diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 062083c47b26..1dfe435ec1e5 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -114,6 +114,7 @@ import android.app.ResultInfo; import android.app.WaitResult; import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; +import android.app.servertransaction.LaunchActivityItem; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -1375,7 +1376,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D r.setLastReportedConfiguration(mergedConfiguration); logIfTransactionTooLarge(r.intent, r.icicle); - app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, + mService.mLifecycleManager.scheduleTransaction(app.thread, r.appToken, + new LaunchActivityItem(new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. @@ -1383,7 +1385,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, - mService.isNextTransitionForward(), profilerInfo); + mService.isNextTransitionForward(), profilerInfo)); if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { // This may be a heavy-weight process! Note that the package diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/am/ClientLifecycleManager.java new file mode 100644 index 000000000000..c04d103c7ff5 --- /dev/null +++ b/services/core/java/com/android/server/am/ClientLifecycleManager.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 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 com.android.server.am; + +import android.annotation.NonNull; +import android.app.IApplicationThread; +import android.app.servertransaction.ClientTransaction; +import android.app.servertransaction.ClientTransactionItem; +import android.app.servertransaction.ActivityLifecycleItem; +import android.os.IBinder; +import android.os.RemoteException; + +/** + * Class that is able to combine multiple client lifecycle transition requests and/or callbacks, + * and execute them as a single transaction. + * + * @see ClientTransaction + */ +class ClientLifecycleManager { + // TODO(lifecycler): Implement building transactions or global transaction. + // TODO(lifecycler): Use object pools for transactions and transaction items. + + /** + * Schedule a transaction, which may consist of multiple callbacks and a lifecycle request. + * @param transaction A sequence of client transaction items. + * @throws RemoteException + * + * @see ClientTransaction + */ + void scheduleTransaction(ClientTransaction transaction) throws RemoteException { + transaction.schedule(); + } + + /** + * Schedule a single lifecycle request or callback to client activity. + * @param client Target client. + * @param activityToken Target activity token. + * @param stateRequest A request to move target activity to a desired lifecycle state. + * @throws RemoteException + * + * @see ClientTransactionItem + */ + void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken, + @NonNull ActivityLifecycleItem stateRequest) throws RemoteException { + final ClientTransaction clientTransaction = transactionWithState(client, activityToken, + stateRequest); + scheduleTransaction(clientTransaction); + } + + /** + * Schedule a single callback delivery to client activity. + * @param client Target client. + * @param activityToken Target activity token. + * @param callback A request to deliver a callback. + * @throws RemoteException + * + * @see ClientTransactionItem + */ + void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken, + @NonNull ClientTransactionItem callback) throws RemoteException { + final ClientTransaction clientTransaction = transactionWithCallback(client, activityToken, + callback); + scheduleTransaction(clientTransaction); + } + + /** + * Schedule a single callback delivery to client application. + * @param client Target client. + * @param callback A request to deliver a callback. + * @throws RemoteException + * + * @see ClientTransactionItem + */ + void scheduleTransaction(@NonNull IApplicationThread client, + @NonNull ClientTransactionItem callback) throws RemoteException { + final ClientTransaction clientTransaction = transactionWithCallback(client, + null /* activityToken */, callback); + scheduleTransaction(clientTransaction); + } + + /** + * @return A new instance of {@link ClientTransaction} with a single lifecycle state request. + * + * @see ClientTransaction + * @see ClientTransactionItem + */ + private static ClientTransaction transactionWithState(@NonNull IApplicationThread client, + @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) { + final ClientTransaction clientTransaction = new ClientTransaction(client, activityToken); + clientTransaction.setLifecycleStateRequest(stateRequest); + return clientTransaction; + } + + /** + * @return A new instance of {@link ClientTransaction} with a single callback invocation. + * + * @see ClientTransaction + * @see ClientTransactionItem + */ + private static ClientTransaction transactionWithCallback(@NonNull IApplicationThread client, + IBinder activityToken, @NonNull ClientTransactionItem callback) { + final ClientTransaction clientTransaction = new ClientTransaction(client, activityToken); + clientTransaction.addCallback(callback); + return clientTransaction; + } +} |