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 static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 22 23 import static java.util.Objects.requireNonNull; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.app.ActivityClient; 28 import android.app.ActivityManager.ProcessState; 29 import android.app.ActivityOptions.SceneTransitionInfo; 30 import android.app.ActivityThread.ActivityClientRecord; 31 import android.app.ClientTransactionHandler; 32 import android.app.IActivityClientController; 33 import android.app.ProfilerInfo; 34 import android.app.ResultInfo; 35 import android.compat.annotation.UnsupportedAppUsage; 36 import android.content.Intent; 37 import android.content.pm.ActivityInfo; 38 import android.content.res.CompatibilityInfo; 39 import android.content.res.Configuration; 40 import android.os.BaseBundle; 41 import android.os.Bundle; 42 import android.os.IBinder; 43 import android.os.Parcel; 44 import android.os.PersistableBundle; 45 import android.os.Trace; 46 import android.window.ActivityWindowInfo; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.app.IVoiceInteractor; 50 import com.android.internal.content.ReferrerIntent; 51 52 import java.util.ArrayList; 53 import java.util.List; 54 import java.util.Objects; 55 56 /** 57 * Request to launch an activity. 58 * 59 * @hide 60 */ 61 public class LaunchActivityItem extends ClientTransactionItem { 62 63 @NonNull 64 private final IBinder mActivityToken; 65 66 // TODO(b/170729553): Mark this with @NonNull and final once @UnsupportedAppUsage removed. 67 // We cannot do it now to avoid app compatibility regression. 68 @UnsupportedAppUsage 69 private Intent mIntent; 70 71 // TODO(b/170729553): Mark this with @NonNull and final once @UnsupportedAppUsage removed. 72 // We cannot do it now to avoid app compatibility regression. 73 @UnsupportedAppUsage 74 private ActivityInfo mInfo; 75 76 @NonNull 77 private final Configuration mCurConfig; 78 79 @NonNull 80 private final Configuration mOverrideConfig; 81 82 @Nullable 83 private final String mReferrer; 84 85 @Nullable 86 private final IVoiceInteractor mVoiceInteractor; 87 88 @Nullable 89 private final Bundle mState; 90 91 @Nullable 92 private final PersistableBundle mPersistentState; 93 94 @Nullable 95 private final List<ResultInfo> mPendingResults; 96 97 @Nullable 98 private final List<ReferrerIntent> mPendingNewIntents; 99 100 @Nullable 101 private final SceneTransitionInfo mSceneTransitionInfo; 102 103 @Nullable 104 private final ProfilerInfo mProfilerInfo; 105 106 @NonNull 107 private final IBinder mAssistToken; 108 109 @NonNull 110 private final IBinder mShareableActivityToken; 111 112 @Nullable 113 private final IBinder mTaskFragmentToken; 114 115 @NonNull 116 private final IBinder mInitialCallerInfoAccessToken; 117 118 @NonNull 119 private final ActivityWindowInfo mActivityWindowInfo; 120 121 /** 122 * It is only non-null if the process is the first time to launch activity. It is only an 123 * optimization for quick look up of the interface so the field is ignored for comparison. 124 */ 125 @Nullable 126 private final IActivityClientController mActivityClientController; 127 128 private final int mIdent; 129 private final int mDeviceId; 130 private final int mProcState; 131 private final boolean mIsForward; 132 private final boolean mLaunchedFromBubble; 133 LaunchActivityItem(@onNull IBinder activityToken, @NonNull Intent intent, int ident, @NonNull ActivityInfo info, @NonNull Configuration curConfig, @NonNull Configuration overrideConfig, int deviceId, @Nullable String referrer, @Nullable IVoiceInteractor voiceInteractor, @ProcessState int procState, @Nullable Bundle state, @Nullable PersistableBundle persistentState, @Nullable List<ResultInfo> pendingResults, @Nullable List<ReferrerIntent> pendingNewIntents, @Nullable SceneTransitionInfo sceneTransitionInfo, boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, @Nullable IActivityClientController activityClientController, @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken, @NonNull ActivityWindowInfo activityWindowInfo)134 public LaunchActivityItem(@NonNull IBinder activityToken, @NonNull Intent intent, 135 int ident, @NonNull ActivityInfo info, @NonNull Configuration curConfig, 136 @NonNull Configuration overrideConfig, int deviceId, @Nullable String referrer, 137 @Nullable IVoiceInteractor voiceInteractor, @ProcessState int procState, 138 @Nullable Bundle state, @Nullable PersistableBundle persistentState, 139 @Nullable List<ResultInfo> pendingResults, 140 @Nullable List<ReferrerIntent> pendingNewIntents, 141 @Nullable SceneTransitionInfo sceneTransitionInfo, 142 boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, 143 @Nullable IActivityClientController activityClientController, 144 @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, 145 @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken, 146 @NonNull ActivityWindowInfo activityWindowInfo) { 147 this(activityToken, ident, new Configuration(curConfig), new Configuration(overrideConfig), 148 deviceId, referrer, voiceInteractor, procState, 149 state != null ? new Bundle(state) : null, 150 persistentState != null ? new PersistableBundle(persistentState) : null, 151 pendingResults != null ? new ArrayList<>(pendingResults) : null, 152 pendingNewIntents != null ? new ArrayList<>(pendingNewIntents) : null, 153 sceneTransitionInfo, isForward, 154 profilerInfo != null ? new ProfilerInfo(profilerInfo) : null, 155 assistToken, activityClientController, shareableActivityToken, launchedFromBubble, 156 taskFragmentToken, initialCallerInfoAccessToken, 157 new ActivityWindowInfo(activityWindowInfo)); 158 mIntent = new Intent(intent); 159 mInfo = new ActivityInfo(info); 160 } 161 162 // TODO(b/170729553): Merge this constructor with previous one if no @UnsupportedAppUsage filed. 163 // We cannot do it now to avoid app compatibility regression. LaunchActivityItem(@onNull IBinder activityToken, int ident, @NonNull Configuration curConfig, @NonNull Configuration overrideConfig, int deviceId, @Nullable String referrer, @Nullable IVoiceInteractor voiceInteractor, @ProcessState int procState, @Nullable Bundle state, @Nullable PersistableBundle persistentState, @Nullable List<ResultInfo> pendingResults, @Nullable List<ReferrerIntent> pendingNewIntents, @Nullable SceneTransitionInfo sceneTransitionInfo, boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, @Nullable IActivityClientController activityClientController, @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken, @NonNull ActivityWindowInfo activityWindowInfo)164 private LaunchActivityItem(@NonNull IBinder activityToken, int ident, 165 @NonNull Configuration curConfig, 166 @NonNull Configuration overrideConfig, int deviceId, @Nullable String referrer, 167 @Nullable IVoiceInteractor voiceInteractor, @ProcessState int procState, 168 @Nullable Bundle state, @Nullable PersistableBundle persistentState, 169 @Nullable List<ResultInfo> pendingResults, 170 @Nullable List<ReferrerIntent> pendingNewIntents, 171 @Nullable SceneTransitionInfo sceneTransitionInfo, 172 boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, 173 @Nullable IActivityClientController activityClientController, 174 @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, 175 @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken, 176 @NonNull ActivityWindowInfo activityWindowInfo) { 177 mActivityToken = activityToken; 178 mIdent = ident; 179 mCurConfig = curConfig; 180 mOverrideConfig = overrideConfig; 181 mDeviceId = deviceId; 182 mReferrer = referrer; 183 mVoiceInteractor = voiceInteractor; 184 mProcState = procState; 185 mState = state; 186 mPersistentState = persistentState; 187 mPendingResults = pendingResults; 188 mPendingNewIntents = pendingNewIntents; 189 mSceneTransitionInfo = sceneTransitionInfo; 190 mIsForward = isForward; 191 mProfilerInfo = profilerInfo; 192 mAssistToken = assistToken; 193 mActivityClientController = activityClientController; 194 mShareableActivityToken = shareableActivityToken; 195 mLaunchedFromBubble = launchedFromBubble; 196 mTaskFragmentToken = taskFragmentToken; 197 mInitialCallerInfoAccessToken = initialCallerInfoAccessToken; 198 mActivityWindowInfo = activityWindowInfo; 199 } 200 201 @Override preExecute(@onNull ClientTransactionHandler client)202 public void preExecute(@NonNull ClientTransactionHandler client) { 203 client.countLaunchingActivities(1); 204 client.updateProcessState(mProcState, false); 205 CompatibilityInfo.applyOverrideIfNeeded(mCurConfig); 206 CompatibilityInfo.applyOverrideIfNeeded(mOverrideConfig); 207 client.updatePendingConfiguration(mCurConfig); 208 if (mActivityClientController != null) { 209 ActivityClient.setActivityClientController(mActivityClientController); 210 } 211 } 212 213 @Override execute(@onNull ClientTransactionHandler client, @NonNull PendingTransactionActions pendingActions)214 public void execute(@NonNull ClientTransactionHandler client, 215 @NonNull PendingTransactionActions pendingActions) { 216 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 217 final ActivityClientRecord r = new ActivityClientRecord(mActivityToken, mIntent, mIdent, 218 mInfo, mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, 219 mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward, 220 mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, 221 mTaskFragmentToken, mInitialCallerInfoAccessToken, mActivityWindowInfo); 222 client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */); 223 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 224 } 225 226 @Override postExecute(@onNull ClientTransactionHandler client, @NonNull PendingTransactionActions pendingActions)227 public void postExecute(@NonNull ClientTransactionHandler client, 228 @NonNull PendingTransactionActions pendingActions) { 229 client.countLaunchingActivities(-1); 230 } 231 232 @VisibleForTesting(visibility = PACKAGE) 233 @NonNull 234 @Override getActivityToken()235 public IBinder getActivityToken() { 236 return mActivityToken; 237 } 238 239 // Parcelable implementation 240 241 /** Writes to Parcel. */ 242 @Override writeToParcel(@onNull Parcel dest, int flags)243 public void writeToParcel(@NonNull Parcel dest, int flags) { 244 dest.writeStrongBinder(mActivityToken); 245 dest.writeInt(mIdent); 246 dest.writeTypedObject(mCurConfig, flags); 247 dest.writeTypedObject(mOverrideConfig, flags); 248 dest.writeInt(mDeviceId); 249 dest.writeString(mReferrer); 250 dest.writeStrongInterface(mVoiceInteractor); 251 dest.writeInt(mProcState); 252 dest.writeBundle(mState); 253 dest.writePersistableBundle(mPersistentState); 254 dest.writeTypedList(mPendingResults, flags); 255 dest.writeTypedList(mPendingNewIntents, flags); 256 dest.writeTypedObject(mSceneTransitionInfo, flags); 257 dest.writeBoolean(mIsForward); 258 dest.writeTypedObject(mProfilerInfo, flags); 259 dest.writeStrongBinder(mAssistToken); 260 dest.writeStrongInterface(mActivityClientController); 261 dest.writeStrongBinder(mShareableActivityToken); 262 dest.writeBoolean(mLaunchedFromBubble); 263 dest.writeStrongBinder(mTaskFragmentToken); 264 dest.writeStrongBinder(mInitialCallerInfoAccessToken); 265 dest.writeTypedObject(mActivityWindowInfo, flags); 266 267 dest.writeTypedObject(mIntent, flags); 268 dest.writeTypedObject(mInfo, flags); 269 } 270 271 /** Reads from Parcel. */ LaunchActivityItem(@onNull Parcel in)272 private LaunchActivityItem(@NonNull Parcel in) { 273 this(in.readStrongBinder() /* activityToken */, 274 in.readInt() /* ident */, 275 requireNonNull(in.readTypedObject(Configuration.CREATOR)) /* curConfig */, 276 requireNonNull(in.readTypedObject(Configuration.CREATOR)) /* overrideConfig */, 277 in.readInt() /* deviceId */, 278 in.readString() /* referrer */, 279 IVoiceInteractor.Stub.asInterface(in.readStrongBinder()) /* voiceInteractor */, 280 in.readInt() /* procState */, 281 in.readBundle(in.getClass().getClassLoader()) /* state */, 282 in.readPersistableBundle(in.getClass().getClassLoader()) /* persistentState */, 283 in.createTypedArrayList(ResultInfo.CREATOR) /* pendingResults */, 284 in.createTypedArrayList(ReferrerIntent.CREATOR) /* pendingNewIntents */, 285 in.readTypedObject(SceneTransitionInfo.CREATOR) /* sceneTransitionInfo */, 286 in.readBoolean() /* isForward */, 287 in.readTypedObject(ProfilerInfo.CREATOR) /* profilerInfo */, 288 in.readStrongBinder() /* assistToken */, 289 IActivityClientController.Stub.asInterface( 290 in.readStrongBinder()) /* activityClientController */, 291 in.readStrongBinder() /* shareableActivityToken */, 292 in.readBoolean() /* launchedFromBubble */, 293 in.readStrongBinder() /* taskFragmentToken */, 294 in.readStrongBinder() /* initialCallerInfoAccessToken */, 295 requireNonNull(in.readTypedObject(ActivityWindowInfo.CREATOR)) 296 /* activityWindowInfo */ 297 ); 298 mIntent = in.readTypedObject(Intent.CREATOR); 299 mInfo = in.readTypedObject(ActivityInfo.CREATOR); 300 } 301 302 public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() { 303 public LaunchActivityItem createFromParcel(@NonNull Parcel in) { 304 return new LaunchActivityItem(in); 305 } 306 307 public LaunchActivityItem[] newArray(int size) { 308 return new LaunchActivityItem[size]; 309 } 310 }; 311 312 @Override equals(@ullable Object o)313 public boolean equals(@Nullable Object o) { 314 if (this == o) { 315 return true; 316 } 317 if (o == null || getClass() != o.getClass()) { 318 return false; 319 } 320 final LaunchActivityItem other = (LaunchActivityItem) o; 321 final boolean intentsEqual = (mIntent == null && other.mIntent == null) 322 || (mIntent != null && mIntent.filterEquals(other.mIntent)); 323 return intentsEqual 324 && Objects.equals(mActivityToken, other.mActivityToken) && mIdent == other.mIdent 325 && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig) 326 && Objects.equals(mOverrideConfig, other.mOverrideConfig) 327 && mDeviceId == other.mDeviceId 328 && Objects.equals(mReferrer, other.mReferrer) 329 && mProcState == other.mProcState && areBundlesEqualRoughly(mState, other.mState) 330 && areBundlesEqualRoughly(mPersistentState, other.mPersistentState) 331 && Objects.equals(mPendingResults, other.mPendingResults) 332 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents) 333 && (mSceneTransitionInfo == null) == (other.mSceneTransitionInfo == null) 334 && mIsForward == other.mIsForward 335 && Objects.equals(mProfilerInfo, other.mProfilerInfo) 336 && Objects.equals(mAssistToken, other.mAssistToken) 337 && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) 338 && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken) 339 && Objects.equals(mInitialCallerInfoAccessToken, 340 other.mInitialCallerInfoAccessToken) 341 && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo); 342 } 343 344 @Override hashCode()345 public int hashCode() { 346 int result = 17; 347 result = 31 * result + Objects.hashCode(mActivityToken); 348 result = 31 * result + mIntent.filterHashCode(); 349 result = 31 * result + mIdent; 350 result = 31 * result + Objects.hashCode(mCurConfig); 351 result = 31 * result + Objects.hashCode(mOverrideConfig); 352 result = 31 * result + mDeviceId; 353 result = 31 * result + Objects.hashCode(mReferrer); 354 result = 31 * result + Objects.hashCode(mProcState); 355 result = 31 * result + getRoughBundleHashCode(mState); 356 result = 31 * result + getRoughBundleHashCode(mPersistentState); 357 result = 31 * result + Objects.hashCode(mPendingResults); 358 result = 31 * result + Objects.hashCode(mPendingNewIntents); 359 result = 31 * result + (mSceneTransitionInfo != null ? 1 : 0); 360 result = 31 * result + (mIsForward ? 1 : 0); 361 result = 31 * result + Objects.hashCode(mProfilerInfo); 362 result = 31 * result + Objects.hashCode(mAssistToken); 363 result = 31 * result + Objects.hashCode(mShareableActivityToken); 364 result = 31 * result + Objects.hashCode(mTaskFragmentToken); 365 result = 31 * result + Objects.hashCode(mInitialCallerInfoAccessToken); 366 result = 31 * result + Objects.hashCode(mActivityWindowInfo); 367 return result; 368 } 369 activityInfoEqual(@ullable ActivityInfo other)370 private boolean activityInfoEqual(@Nullable ActivityInfo other) { 371 if (mInfo == null) { 372 return other == null; 373 } 374 return other != null && mInfo.flags == other.flags 375 && mInfo.getMaxAspectRatio() == other.getMaxAspectRatio() 376 && Objects.equals(mInfo.launchToken, other.launchToken) 377 && Objects.equals(mInfo.getComponentName(), other.getComponentName()); 378 } 379 380 /** 381 * This method may be used to compare a parceled item with another unparceled item, and the 382 * parceled bundle may contain customized class that will raise BadParcelableException when 383 * unparceling if a customized class loader is not set to the bundle. So the hash code is 384 * simply determined by the bundle is empty or not. 385 */ getRoughBundleHashCode(@ullable BaseBundle bundle)386 private static int getRoughBundleHashCode(@Nullable BaseBundle bundle) { 387 return (bundle == null || bundle.isDefinitelyEmpty()) ? 0 : 1; 388 } 389 390 /** Compares the bundles without unparceling them (avoid BadParcelableException). */ areBundlesEqualRoughly(@ullable BaseBundle a, @Nullable BaseBundle b)391 private static boolean areBundlesEqualRoughly(@Nullable BaseBundle a, @Nullable BaseBundle b) { 392 return getRoughBundleHashCode(a) == getRoughBundleHashCode(b); 393 } 394 395 @Override toString()396 public String toString() { 397 return "LaunchActivityItem{activityToken=" + mActivityToken 398 + ",intent=" + mIntent 399 + ",ident=" + mIdent 400 + ",info=" + mInfo 401 + ",curConfig=" + mCurConfig 402 + ",overrideConfig=" + mOverrideConfig 403 + ",deviceId=" + mDeviceId 404 + ",referrer=" + mReferrer 405 + ",procState=" + mProcState 406 + ",state=" + mState 407 + ",persistentState=" + mPersistentState 408 + ",pendingResults=" + mPendingResults 409 + ",pendingNewIntents=" + mPendingNewIntents 410 + ",sceneTransitionInfo=" + mSceneTransitionInfo 411 + ",profilerInfo=" + mProfilerInfo 412 + ",assistToken=" + mAssistToken 413 + ",shareableActivityToken=" + mShareableActivityToken 414 + ",activityWindowInfo=" + mActivityWindowInfo 415 + "}"; 416 } 417 } 418