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.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.ActivityClient; 24 import android.app.ActivityOptions; 25 import android.app.ActivityThread.ActivityClientRecord; 26 import android.app.ClientTransactionHandler; 27 import android.app.IActivityClientController; 28 import android.app.ProfilerInfo; 29 import android.app.ResultInfo; 30 import android.compat.annotation.UnsupportedAppUsage; 31 import android.content.Intent; 32 import android.content.pm.ActivityInfo; 33 import android.content.res.CompatibilityInfo; 34 import android.content.res.Configuration; 35 import android.os.BaseBundle; 36 import android.os.Bundle; 37 import android.os.IBinder; 38 import android.os.Parcel; 39 import android.os.PersistableBundle; 40 import android.os.Trace; 41 42 import com.android.internal.app.IVoiceInteractor; 43 import com.android.internal.content.ReferrerIntent; 44 45 import java.util.List; 46 import java.util.Objects; 47 48 /** 49 * Request to launch an activity. 50 * @hide 51 */ 52 public class LaunchActivityItem extends ClientTransactionItem { 53 54 @UnsupportedAppUsage 55 private Intent mIntent; 56 private int mIdent; 57 @UnsupportedAppUsage 58 private ActivityInfo mInfo; 59 private Configuration mCurConfig; 60 private Configuration mOverrideConfig; 61 private CompatibilityInfo mCompatInfo; 62 private String mReferrer; 63 private IVoiceInteractor mVoiceInteractor; 64 private int mProcState; 65 private Bundle mState; 66 private PersistableBundle mPersistentState; 67 private List<ResultInfo> mPendingResults; 68 private List<ReferrerIntent> mPendingNewIntents; 69 private ActivityOptions mActivityOptions; 70 private boolean mIsForward; 71 private ProfilerInfo mProfilerInfo; 72 private IBinder mAssistToken; 73 private IBinder mShareableActivityToken; 74 private boolean mLaunchedFromBubble; 75 private IBinder mTaskFragmentToken; 76 /** 77 * It is only non-null if the process is the first time to launch activity. It is only an 78 * optimization for quick look up of the interface so the field is ignored for comparison. 79 */ 80 private IActivityClientController mActivityClientController; 81 82 @Override preExecute(ClientTransactionHandler client, IBinder token)83 public void preExecute(ClientTransactionHandler client, IBinder token) { 84 client.countLaunchingActivities(1); 85 client.updateProcessState(mProcState, false); 86 client.updatePendingConfiguration(mCurConfig); 87 if (mActivityClientController != null) { 88 ActivityClient.setActivityClientController(mActivityClientController); 89 } 90 } 91 92 @Override execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)93 public void execute(ClientTransactionHandler client, IBinder token, 94 PendingTransactionActions pendingActions) { 95 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 96 ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, 97 mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, 98 mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, 99 client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, 100 mTaskFragmentToken); 101 client.handleLaunchActivity(r, pendingActions, null /* customIntent */); 102 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 103 } 104 105 @Override postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)106 public void postExecute(ClientTransactionHandler client, IBinder token, 107 PendingTransactionActions pendingActions) { 108 client.countLaunchingActivities(-1); 109 } 110 111 112 // ObjectPoolItem implementation 113 LaunchActivityItem()114 private LaunchActivityItem() {} 115 116 /** Obtain an instance initialized with provided params. */ obtain(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, ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, IActivityClientController activityClientController, IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken)117 public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info, 118 Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, 119 String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, 120 PersistableBundle persistentState, List<ResultInfo> pendingResults, 121 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, 122 boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, 123 IActivityClientController activityClientController, IBinder shareableActivityToken, 124 boolean launchedFromBubble, IBinder taskFragmentToken) { 125 LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); 126 if (instance == null) { 127 instance = new LaunchActivityItem(); 128 } 129 setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer, 130 voiceInteractor, procState, state, persistentState, pendingResults, 131 pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken, 132 activityClientController, shareableActivityToken, 133 launchedFromBubble, taskFragmentToken); 134 135 return instance; 136 } 137 138 @Override recycle()139 public void recycle() { 140 setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null, 141 null, false, null, null, null, null, false, null); 142 ObjectPool.recycle(this); 143 } 144 145 146 // Parcelable implementation 147 148 /** Write from Parcel. */ 149 @Override writeToParcel(Parcel dest, int flags)150 public void writeToParcel(Parcel dest, int flags) { 151 dest.writeTypedObject(mIntent, flags); 152 dest.writeInt(mIdent); 153 dest.writeTypedObject(mInfo, flags); 154 dest.writeTypedObject(mCurConfig, flags); 155 dest.writeTypedObject(mOverrideConfig, flags); 156 dest.writeTypedObject(mCompatInfo, flags); 157 dest.writeString(mReferrer); 158 dest.writeStrongInterface(mVoiceInteractor); 159 dest.writeInt(mProcState); 160 dest.writeBundle(mState); 161 dest.writePersistableBundle(mPersistentState); 162 dest.writeTypedList(mPendingResults, flags); 163 dest.writeTypedList(mPendingNewIntents, flags); 164 dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null); 165 dest.writeBoolean(mIsForward); 166 dest.writeTypedObject(mProfilerInfo, flags); 167 dest.writeStrongBinder(mAssistToken); 168 dest.writeStrongInterface(mActivityClientController); 169 dest.writeStrongBinder(mShareableActivityToken); 170 dest.writeBoolean(mLaunchedFromBubble); 171 dest.writeStrongBinder(mTaskFragmentToken); 172 } 173 174 /** Read from Parcel. */ LaunchActivityItem(Parcel in)175 private LaunchActivityItem(Parcel in) { 176 setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(), 177 in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR), 178 in.readTypedObject(Configuration.CREATOR), 179 in.readTypedObject(CompatibilityInfo.CREATOR), in.readString(), 180 IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(), 181 in.readBundle(getClass().getClassLoader()), 182 in.readPersistableBundle(getClass().getClassLoader()), 183 in.createTypedArrayList(ResultInfo.CREATOR), 184 in.createTypedArrayList(ReferrerIntent.CREATOR), 185 ActivityOptions.fromBundle(in.readBundle()), in.readBoolean(), 186 in.readTypedObject(ProfilerInfo.CREATOR), 187 in.readStrongBinder(), 188 IActivityClientController.Stub.asInterface(in.readStrongBinder()), 189 in.readStrongBinder(), 190 in.readBoolean(), 191 in.readStrongBinder()); 192 } 193 194 public static final @NonNull Creator<LaunchActivityItem> CREATOR = 195 new Creator<LaunchActivityItem>() { 196 public LaunchActivityItem createFromParcel(Parcel in) { 197 return new LaunchActivityItem(in); 198 } 199 200 public LaunchActivityItem[] newArray(int size) { 201 return new LaunchActivityItem[size]; 202 } 203 }; 204 205 @Override equals(@ullable Object o)206 public boolean equals(@Nullable Object o) { 207 if (this == o) { 208 return true; 209 } 210 if (o == null || getClass() != o.getClass()) { 211 return false; 212 } 213 final LaunchActivityItem other = (LaunchActivityItem) o; 214 final boolean intentsEqual = (mIntent == null && other.mIntent == null) 215 || (mIntent != null && mIntent.filterEquals(other.mIntent)); 216 return intentsEqual && mIdent == other.mIdent 217 && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig) 218 && Objects.equals(mOverrideConfig, other.mOverrideConfig) 219 && Objects.equals(mCompatInfo, other.mCompatInfo) 220 && Objects.equals(mReferrer, other.mReferrer) 221 && mProcState == other.mProcState && areBundlesEqualRoughly(mState, other.mState) 222 && areBundlesEqualRoughly(mPersistentState, other.mPersistentState) 223 && Objects.equals(mPendingResults, other.mPendingResults) 224 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents) 225 && (mActivityOptions == null) == (other.mActivityOptions == null) 226 && mIsForward == other.mIsForward 227 && Objects.equals(mProfilerInfo, other.mProfilerInfo) 228 && Objects.equals(mAssistToken, other.mAssistToken) 229 && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) 230 && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken); 231 } 232 233 @Override hashCode()234 public int hashCode() { 235 int result = 17; 236 result = 31 * result + mIntent.filterHashCode(); 237 result = 31 * result + mIdent; 238 result = 31 * result + Objects.hashCode(mCurConfig); 239 result = 31 * result + Objects.hashCode(mOverrideConfig); 240 result = 31 * result + Objects.hashCode(mCompatInfo); 241 result = 31 * result + Objects.hashCode(mReferrer); 242 result = 31 * result + Objects.hashCode(mProcState); 243 result = 31 * result + getRoughBundleHashCode(mState); 244 result = 31 * result + getRoughBundleHashCode(mPersistentState); 245 result = 31 * result + Objects.hashCode(mPendingResults); 246 result = 31 * result + Objects.hashCode(mPendingNewIntents); 247 result = 31 * result + (mActivityOptions != null ? 1 : 0); 248 result = 31 * result + (mIsForward ? 1 : 0); 249 result = 31 * result + Objects.hashCode(mProfilerInfo); 250 result = 31 * result + Objects.hashCode(mAssistToken); 251 result = 31 * result + Objects.hashCode(mShareableActivityToken); 252 result = 31 * result + Objects.hashCode(mTaskFragmentToken); 253 return result; 254 } 255 activityInfoEqual(ActivityInfo other)256 private boolean activityInfoEqual(ActivityInfo other) { 257 if (mInfo == null) { 258 return other == null; 259 } 260 return other != null && mInfo.flags == other.flags 261 && mInfo.getMaxAspectRatio() == other.getMaxAspectRatio() 262 && Objects.equals(mInfo.launchToken, other.launchToken) 263 && Objects.equals(mInfo.getComponentName(), other.getComponentName()); 264 } 265 266 /** 267 * This method may be used to compare a parceled item with another unparceled item, and the 268 * parceled bundle may contain customized class that will raise BadParcelableException when 269 * unparceling if a customized class loader is not set to the bundle. So the hash code is 270 * simply determined by the bundle is empty or not. 271 */ getRoughBundleHashCode(BaseBundle bundle)272 private static int getRoughBundleHashCode(BaseBundle bundle) { 273 return (bundle == null || bundle.isDefinitelyEmpty()) ? 0 : 1; 274 } 275 276 /** Compares the bundles without unparceling them (avoid BadParcelableException). */ areBundlesEqualRoughly(BaseBundle a, BaseBundle b)277 private static boolean areBundlesEqualRoughly(BaseBundle a, BaseBundle b) { 278 return getRoughBundleHashCode(a) == getRoughBundleHashCode(b); 279 } 280 281 @Override toString()282 public String toString() { 283 return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo 284 + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig 285 + ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState 286 + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults 287 + ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions 288 + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken 289 + ",shareableActivityToken=" + mShareableActivityToken + "}"; 290 } 291 292 // Using the same method to set and clear values to make sure we don't forget anything setValues(LaunchActivityItem instance, 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, ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, IActivityClientController activityClientController, IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken)293 private static void setValues(LaunchActivityItem instance, Intent intent, int ident, 294 ActivityInfo info, Configuration curConfig, Configuration overrideConfig, 295 CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, 296 int procState, Bundle state, PersistableBundle persistentState, 297 List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, 298 ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, 299 IBinder assistToken, IActivityClientController activityClientController, 300 IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken) { 301 instance.mIntent = intent; 302 instance.mIdent = ident; 303 instance.mInfo = info; 304 instance.mCurConfig = curConfig; 305 instance.mOverrideConfig = overrideConfig; 306 instance.mCompatInfo = compatInfo; 307 instance.mReferrer = referrer; 308 instance.mVoiceInteractor = voiceInteractor; 309 instance.mProcState = procState; 310 instance.mState = state; 311 instance.mPersistentState = persistentState; 312 instance.mPendingResults = pendingResults; 313 instance.mPendingNewIntents = pendingNewIntents; 314 instance.mActivityOptions = activityOptions; 315 instance.mIsForward = isForward; 316 instance.mProfilerInfo = profilerInfo; 317 instance.mAssistToken = assistToken; 318 instance.mActivityClientController = activityClientController; 319 instance.mShareableActivityToken = shareableActivityToken; 320 instance.mLaunchedFromBubble = launchedFromBubble; 321 instance.mTaskFragmentToken = taskFragmentToken; 322 } 323 } 324