1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.servertransaction;
18 
19 import static android.app.ActivityThread.DEBUG_MEMORY_TRIM;
20 
21 import android.app.ActivityManager;
22 import android.app.ActivityThread.ActivityClientRecord;
23 import android.os.Build;
24 import android.os.Bundle;
25 import android.os.PersistableBundle;
26 import android.os.RemoteException;
27 import android.os.TransactionTooLargeException;
28 import android.util.Log;
29 import android.util.LogWriter;
30 import android.util.Slog;
31 
32 import com.android.internal.util.IndentingPrintWriter;
33 
34 /**
35  * Container that has data pending to be used at later stages of
36  * {@link android.app.servertransaction.ClientTransaction}.
37  * An instance of this class is passed to each individual transaction item, so it can use some
38  * information from previous steps or add some for the following steps.
39  *
40  * @hide
41  */
42 public class PendingTransactionActions {
43     private boolean mRestoreInstanceState;
44     private boolean mCallOnPostCreate;
45     private Bundle mOldState;
46     private StopInfo mStopInfo;
47     private boolean mReportRelaunchToWM;
48 
PendingTransactionActions()49     public PendingTransactionActions() {
50         clear();
51     }
52 
53     /** Reset the state of the instance to default, non-initialized values. */
clear()54     public void clear() {
55         mRestoreInstanceState = false;
56         mCallOnPostCreate = false;
57         mOldState = null;
58         mStopInfo = null;
59     }
60 
61     /** Getter */
shouldRestoreInstanceState()62     public boolean shouldRestoreInstanceState() {
63         return mRestoreInstanceState;
64     }
65 
setRestoreInstanceState(boolean restoreInstanceState)66     public void setRestoreInstanceState(boolean restoreInstanceState) {
67         mRestoreInstanceState = restoreInstanceState;
68     }
69 
70     /** Getter */
shouldCallOnPostCreate()71     public boolean shouldCallOnPostCreate() {
72         return mCallOnPostCreate;
73     }
74 
setCallOnPostCreate(boolean callOnPostCreate)75     public void setCallOnPostCreate(boolean callOnPostCreate) {
76         mCallOnPostCreate = callOnPostCreate;
77     }
78 
getOldState()79     public Bundle getOldState() {
80         return mOldState;
81     }
82 
setOldState(Bundle oldState)83     public void setOldState(Bundle oldState) {
84         mOldState = oldState;
85     }
86 
getStopInfo()87     public StopInfo getStopInfo() {
88         return mStopInfo;
89     }
90 
setStopInfo(StopInfo stopInfo)91     public void setStopInfo(StopInfo stopInfo) {
92         mStopInfo = stopInfo;
93     }
94 
95     /**
96      * Check if we should report an activity relaunch to WindowManager. We report back for every
97      * relaunch request to ActivityManager, but only for those that were actually finished to we
98      * report to WindowManager.
99      */
shouldReportRelaunchToWindowManager()100     public boolean shouldReportRelaunchToWindowManager() {
101         return mReportRelaunchToWM;
102     }
103 
104     /**
105      * Set if we should report an activity relaunch to WindowManager. We report back for every
106      * relaunch request to ActivityManager, but only for those that were actually finished we report
107      * to WindowManager.
108      */
setReportRelaunchToWindowManager(boolean reportToWm)109     public void setReportRelaunchToWindowManager(boolean reportToWm) {
110         mReportRelaunchToWM = reportToWm;
111     }
112 
113     /** Reports to server about activity stop. */
114     public static class StopInfo implements Runnable {
115         private static final String TAG = "ActivityStopInfo";
116 
117         private ActivityClientRecord mActivity;
118         private Bundle mState;
119         private PersistableBundle mPersistentState;
120         private CharSequence mDescription;
121 
setActivity(ActivityClientRecord activity)122         public void setActivity(ActivityClientRecord activity) {
123             mActivity = activity;
124         }
125 
setState(Bundle state)126         public void setState(Bundle state) {
127             mState = state;
128         }
129 
setPersistentState(PersistableBundle persistentState)130         public void setPersistentState(PersistableBundle persistentState) {
131             mPersistentState = persistentState;
132         }
133 
setDescription(CharSequence description)134         public void setDescription(CharSequence description) {
135             mDescription = description;
136         }
137 
138         @Override
run()139         public void run() {
140             // Tell activity manager we have been stopped.
141             try {
142                 if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity);
143                 // TODO(lifecycler): Use interface callback instead of AMS.
144                 ActivityManager.getService().activityStopped(
145                         mActivity.token, mState, mPersistentState, mDescription);
146             } catch (RemoteException ex) {
147                 // Dump statistics about bundle to help developers debug
148                 final LogWriter writer = new LogWriter(Log.WARN, TAG);
149                 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
150                 pw.println("Bundle stats:");
151                 Bundle.dumpStats(pw, mState);
152                 pw.println("PersistableBundle stats:");
153                 Bundle.dumpStats(pw, mPersistentState);
154 
155                 if (ex instanceof TransactionTooLargeException
156                         && mActivity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
157                     Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
158                     return;
159                 }
160                 throw ex.rethrowFromSystemServer();
161             }
162         }
163     }
164 }
165