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
17package android.app.servertransaction;
18
19import static android.app.ActivityThread.DEBUG_MEMORY_TRIM;
20
21import android.app.ActivityManager;
22import android.app.ActivityThread.ActivityClientRecord;
23import android.os.Build;
24import android.os.Bundle;
25import android.os.PersistableBundle;
26import android.os.RemoteException;
27import android.os.TransactionTooLargeException;
28import android.util.Log;
29import android.util.LogWriter;
30import android.util.Slog;
31
32import 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 */
42public class PendingTransactionActions {
43    private boolean mRestoreInstanceState;
44    private boolean mCallOnPostCreate;
45    private Bundle mOldState;
46    private StopInfo mStopInfo;
47    private boolean mReportRelaunchToWM;
48
49    public PendingTransactionActions() {
50        clear();
51    }
52
53    /** Reset the state of the instance to default, non-initialized values. */
54    public void clear() {
55        mRestoreInstanceState = false;
56        mCallOnPostCreate = false;
57        mOldState = null;
58        mStopInfo = null;
59    }
60
61    /** Getter */
62    public boolean shouldRestoreInstanceState() {
63        return mRestoreInstanceState;
64    }
65
66    public void setRestoreInstanceState(boolean restoreInstanceState) {
67        mRestoreInstanceState = restoreInstanceState;
68    }
69
70    /** Getter */
71    public boolean shouldCallOnPostCreate() {
72        return mCallOnPostCreate;
73    }
74
75    public void setCallOnPostCreate(boolean callOnPostCreate) {
76        mCallOnPostCreate = callOnPostCreate;
77    }
78
79    public Bundle getOldState() {
80        return mOldState;
81    }
82
83    public void setOldState(Bundle oldState) {
84        mOldState = oldState;
85    }
86
87    public StopInfo getStopInfo() {
88        return mStopInfo;
89    }
90
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     */
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     */
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
122        public void setActivity(ActivityClientRecord activity) {
123            mActivity = activity;
124        }
125
126        public void setState(Bundle state) {
127            mState = state;
128        }
129
130        public void setPersistentState(PersistableBundle persistentState) {
131            mPersistentState = persistentState;
132        }
133
134        public void setDescription(CharSequence description) {
135            mDescription = description;
136        }
137
138        @Override
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