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.ActivityTaskManager;
23 import android.app.ActivityThread.ActivityClientRecord;
24 import android.os.Build;
25 import android.os.Bundle;
26 import android.os.PersistableBundle;
27 import android.os.RemoteException;
28 import android.os.TransactionTooLargeException;
29 import android.util.Log;
30 import android.util.LogWriter;
31 import android.util.Slog;
32 
33 import com.android.internal.util.IndentingPrintWriter;
34 
35 /**
36  * Container that has data pending to be used at later stages of
37  * {@link android.app.servertransaction.ClientTransaction}.
38  * An instance of this class is passed to each individual transaction item, so it can use some
39  * information from previous steps or add some for the following steps.
40  *
41  * @hide
42  */
43 public class PendingTransactionActions {
44     private boolean mRestoreInstanceState;
45     private boolean mCallOnPostCreate;
46     private Bundle mOldState;
47     private StopInfo mStopInfo;
48     private boolean mReportRelaunchToWM;
49 
PendingTransactionActions()50     public PendingTransactionActions() {
51         clear();
52     }
53 
54     /** Reset the state of the instance to default, non-initialized values. */
clear()55     public void clear() {
56         mRestoreInstanceState = false;
57         mCallOnPostCreate = false;
58         mOldState = null;
59         mStopInfo = null;
60     }
61 
62     /** Getter */
shouldRestoreInstanceState()63     public boolean shouldRestoreInstanceState() {
64         return mRestoreInstanceState;
65     }
66 
setRestoreInstanceState(boolean restoreInstanceState)67     public void setRestoreInstanceState(boolean restoreInstanceState) {
68         mRestoreInstanceState = restoreInstanceState;
69     }
70 
71     /** Getter */
shouldCallOnPostCreate()72     public boolean shouldCallOnPostCreate() {
73         return mCallOnPostCreate;
74     }
75 
setCallOnPostCreate(boolean callOnPostCreate)76     public void setCallOnPostCreate(boolean callOnPostCreate) {
77         mCallOnPostCreate = callOnPostCreate;
78     }
79 
getOldState()80     public Bundle getOldState() {
81         return mOldState;
82     }
83 
setOldState(Bundle oldState)84     public void setOldState(Bundle oldState) {
85         mOldState = oldState;
86     }
87 
getStopInfo()88     public StopInfo getStopInfo() {
89         return mStopInfo;
90     }
91 
setStopInfo(StopInfo stopInfo)92     public void setStopInfo(StopInfo stopInfo) {
93         mStopInfo = stopInfo;
94     }
95 
96     /**
97      * Check if we should report an activity relaunch to WindowManager. We report back for every
98      * relaunch request to ActivityManager, but only for those that were actually finished to we
99      * report to WindowManager.
100      */
shouldReportRelaunchToWindowManager()101     public boolean shouldReportRelaunchToWindowManager() {
102         return mReportRelaunchToWM;
103     }
104 
105     /**
106      * Set if we should report an activity relaunch to WindowManager. We report back for every
107      * relaunch request to ActivityManager, but only for those that were actually finished we report
108      * to WindowManager.
109      */
setReportRelaunchToWindowManager(boolean reportToWm)110     public void setReportRelaunchToWindowManager(boolean reportToWm) {
111         mReportRelaunchToWM = reportToWm;
112     }
113 
114     /** Reports to server about activity stop. */
115     public static class StopInfo implements Runnable {
116         private static final String TAG = "ActivityStopInfo";
117 
118         private ActivityClientRecord mActivity;
119         private Bundle mState;
120         private PersistableBundle mPersistentState;
121         private CharSequence mDescription;
122 
setActivity(ActivityClientRecord activity)123         public void setActivity(ActivityClientRecord activity) {
124             mActivity = activity;
125         }
126 
setState(Bundle state)127         public void setState(Bundle state) {
128             mState = state;
129         }
130 
setPersistentState(PersistableBundle persistentState)131         public void setPersistentState(PersistableBundle persistentState) {
132             mPersistentState = persistentState;
133         }
134 
setDescription(CharSequence description)135         public void setDescription(CharSequence description) {
136             mDescription = description;
137         }
138 
139         @Override
run()140         public void run() {
141             // Tell activity manager we have been stopped.
142             try {
143                 if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity);
144                 // TODO(lifecycler): Use interface callback instead of AMS.
145                 ActivityTaskManager.getService().activityStopped(
146                         mActivity.token, mState, mPersistentState, mDescription);
147             } catch (RemoteException ex) {
148                 // Dump statistics about bundle to help developers debug
149                 final LogWriter writer = new LogWriter(Log.WARN, TAG);
150                 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
151                 pw.println("Bundle stats:");
152                 Bundle.dumpStats(pw, mState);
153                 pw.println("PersistableBundle stats:");
154                 Bundle.dumpStats(pw, mPersistentState);
155 
156                 if (ex instanceof TransactionTooLargeException
157                         && mActivity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
158                     Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
159                     return;
160                 }
161                 throw ex.rethrowFromSystemServer();
162             }
163         }
164     }
165 }
166