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.ActivityClient; 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.TransactionTooLargeException; 27 import android.util.Log; 28 import android.util.Slog; 29 30 import com.android.internal.util.IndentingPrintWriter; 31 32 import java.io.StringWriter; 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 PendingTransactionActions()48 public PendingTransactionActions() { 49 clear(); 50 } 51 52 /** Reset the state of the instance to default, non-initialized values. */ clear()53 public void clear() { 54 mRestoreInstanceState = false; 55 mCallOnPostCreate = false; 56 mOldState = null; 57 mStopInfo = null; 58 } 59 60 /** Getter */ shouldRestoreInstanceState()61 public boolean shouldRestoreInstanceState() { 62 return mRestoreInstanceState; 63 } 64 setRestoreInstanceState(boolean restoreInstanceState)65 public void setRestoreInstanceState(boolean restoreInstanceState) { 66 mRestoreInstanceState = restoreInstanceState; 67 } 68 69 /** Getter */ shouldCallOnPostCreate()70 public boolean shouldCallOnPostCreate() { 71 return mCallOnPostCreate; 72 } 73 setCallOnPostCreate(boolean callOnPostCreate)74 public void setCallOnPostCreate(boolean callOnPostCreate) { 75 mCallOnPostCreate = callOnPostCreate; 76 } 77 getOldState()78 public Bundle getOldState() { 79 return mOldState; 80 } 81 setOldState(Bundle oldState)82 public void setOldState(Bundle oldState) { 83 mOldState = oldState; 84 } 85 getStopInfo()86 public StopInfo getStopInfo() { 87 return mStopInfo; 88 } 89 setStopInfo(StopInfo stopInfo)90 public void setStopInfo(StopInfo stopInfo) { 91 mStopInfo = stopInfo; 92 } 93 94 /** Reports to server about activity stop. */ 95 public static class StopInfo implements Runnable { 96 private static final String TAG = "ActivityStopInfo"; 97 98 private ActivityClientRecord mActivity; 99 private Bundle mState; 100 private PersistableBundle mPersistentState; 101 private CharSequence mDescription; 102 setActivity(ActivityClientRecord activity)103 public void setActivity(ActivityClientRecord activity) { 104 mActivity = activity; 105 } 106 setState(Bundle state)107 public void setState(Bundle state) { 108 mState = state; 109 } 110 setPersistentState(PersistableBundle persistentState)111 public void setPersistentState(PersistableBundle persistentState) { 112 mPersistentState = persistentState; 113 } 114 setDescription(CharSequence description)115 public void setDescription(CharSequence description) { 116 mDescription = description; 117 } 118 collectBundleStates()119 private String collectBundleStates() { 120 final StringWriter writer = new StringWriter(); 121 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 122 pw.println("Bundle stats:"); 123 Bundle.dumpStats(pw, mState); 124 pw.println("PersistableBundle stats:"); 125 Bundle.dumpStats(pw, mPersistentState); 126 return writer.toString().stripTrailing(); 127 } 128 129 @Override run()130 public void run() { 131 // Tell activity manager we have been stopped. 132 try { 133 if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity); 134 // TODO(lifecycler): Use interface callback instead of AMS. 135 ActivityClient.getInstance().activityStopped( 136 mActivity.token, mState, mPersistentState, mDescription); 137 } catch (RuntimeException runtimeException) { 138 // Collect the statistics about bundle 139 final String bundleStats = collectBundleStates(); 140 141 RuntimeException ex = runtimeException; 142 if (ex.getCause() instanceof TransactionTooLargeException) { 143 // Embed the stats into exception message to help developers debug if the 144 // transaction size is too large. 145 final String message = ex.getMessage() + "\n" + bundleStats; 146 ex = new RuntimeException(message, ex.getCause()); 147 if (mActivity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) { 148 Log.e(TAG, "App sent too much data in instance state, so it was ignored", 149 ex); 150 return; 151 } 152 } else { 153 // Otherwise, dump the stats anyway. 154 Log.w(TAG, bundleStats); 155 } 156 throw ex; 157 } 158 } 159 } 160 } 161