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 int mDeviceId; 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 CompatibilityInfo.applyOverrideScaleIfNeeded(mCurConfig); 87 CompatibilityInfo.applyOverrideScaleIfNeeded(mOverrideConfig); 88 client.updatePendingConfiguration(mCurConfig); 89 if (mActivityClientController != null) { 90 ActivityClient.setActivityClientController(mActivityClientController); 91 } 92 } 93 94 @Override execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)95 public void execute(ClientTransactionHandler client, IBinder token, 96 PendingTransactionActions pendingActions) { 97 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 98 ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, 99 mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, 100 mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, 101 client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, 102 mTaskFragmentToken); 103 client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */); 104 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 105 } 106 107 @Override postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)108 public void postExecute(ClientTransactionHandler client, IBinder token, 109 PendingTransactionActions pendingActions) { 110 client.countLaunchingActivities(-1); 111 } 112 113 114 // ObjectPoolItem implementation 115 LaunchActivityItem()116 private LaunchActivityItem() {} 117 118 /** Obtain an instance initialized with provided params. */ obtain(Intent intent, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, int deviceId, 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)119 public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info, 120 Configuration curConfig, Configuration overrideConfig, int deviceId, 121 String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, 122 PersistableBundle persistentState, List<ResultInfo> pendingResults, 123 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, 124 boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, 125 IActivityClientController activityClientController, IBinder shareableActivityToken, 126 boolean launchedFromBubble, IBinder taskFragmentToken) { 127 LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); 128 if (instance == null) { 129 instance = new LaunchActivityItem(); 130 } 131 setValues(instance, intent, ident, info, curConfig, overrideConfig, deviceId, referrer, 132 voiceInteractor, procState, state, persistentState, pendingResults, 133 pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken, 134 activityClientController, shareableActivityToken, 135 launchedFromBubble, taskFragmentToken); 136 137 return instance; 138 } 139 140 @Override recycle()141 public void recycle() { 142 setValues(this, null, 0, null, null, null, 0, null, null, 0, null, null, null, null, 143 null, false, null, null, null, null, false, null); 144 ObjectPool.recycle(this); 145 } 146 147 148 // Parcelable implementation 149 150 /** Write from Parcel. */ 151 @Override writeToParcel(Parcel dest, int flags)152 public void writeToParcel(Parcel dest, int flags) { 153 dest.writeTypedObject(mIntent, flags); 154 dest.writeInt(mIdent); 155 dest.writeTypedObject(mInfo, flags); 156 dest.writeTypedObject(mCurConfig, flags); 157 dest.writeTypedObject(mOverrideConfig, flags); 158 dest.writeInt(mDeviceId); 159 dest.writeString(mReferrer); 160 dest.writeStrongInterface(mVoiceInteractor); 161 dest.writeInt(mProcState); 162 dest.writeBundle(mState); 163 dest.writePersistableBundle(mPersistentState); 164 dest.writeTypedList(mPendingResults, flags); 165 dest.writeTypedList(mPendingNewIntents, flags); 166 dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null); 167 dest.writeBoolean(mIsForward); 168 dest.writeTypedObject(mProfilerInfo, flags); 169 dest.writeStrongBinder(mAssistToken); 170 dest.writeStrongInterface(mActivityClientController); 171 dest.writeStrongBinder(mShareableActivityToken); 172 dest.writeBoolean(mLaunchedFromBubble); 173 dest.writeStrongBinder(mTaskFragmentToken); 174 } 175 176 /** Read from Parcel. */ LaunchActivityItem(Parcel in)177 private LaunchActivityItem(Parcel in) { 178 setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(), 179 in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR), 180 in.readTypedObject(Configuration.CREATOR), in.readInt(), in.readString(), 181 IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(), 182 in.readBundle(getClass().getClassLoader()), 183 in.readPersistableBundle(getClass().getClassLoader()), 184 in.createTypedArrayList(ResultInfo.CREATOR), 185 in.createTypedArrayList(ReferrerIntent.CREATOR), 186 ActivityOptions.fromBundle(in.readBundle()), in.readBoolean(), 187 in.readTypedObject(ProfilerInfo.CREATOR), 188 in.readStrongBinder(), 189 IActivityClientController.Stub.asInterface(in.readStrongBinder()), 190 in.readStrongBinder(), 191 in.readBoolean(), 192 in.readStrongBinder()); 193 } 194 195 public static final @NonNull Creator<LaunchActivityItem> CREATOR = 196 new Creator<LaunchActivityItem>() { 197 public LaunchActivityItem createFromParcel(Parcel in) { 198 return new LaunchActivityItem(in); 199 } 200 201 public LaunchActivityItem[] newArray(int size) { 202 return new LaunchActivityItem[size]; 203 } 204 }; 205 206 @Override equals(@ullable Object o)207 public boolean equals(@Nullable Object o) { 208 if (this == o) { 209 return true; 210 } 211 if (o == null || getClass() != o.getClass()) { 212 return false; 213 } 214 final LaunchActivityItem other = (LaunchActivityItem) o; 215 final boolean intentsEqual = (mIntent == null && other.mIntent == null) 216 || (mIntent != null && mIntent.filterEquals(other.mIntent)); 217 return intentsEqual && mIdent == other.mIdent 218 && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig) 219 && Objects.equals(mOverrideConfig, other.mOverrideConfig) 220 && mDeviceId == other.mDeviceId 221 && Objects.equals(mReferrer, other.mReferrer) 222 && mProcState == other.mProcState && areBundlesEqualRoughly(mState, other.mState) 223 && areBundlesEqualRoughly(mPersistentState, other.mPersistentState) 224 && Objects.equals(mPendingResults, other.mPendingResults) 225 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents) 226 && (mActivityOptions == null) == (other.mActivityOptions == null) 227 && mIsForward == other.mIsForward 228 && Objects.equals(mProfilerInfo, other.mProfilerInfo) 229 && Objects.equals(mAssistToken, other.mAssistToken) 230 && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) 231 && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken); 232 } 233 234 @Override hashCode()235 public int hashCode() { 236 int result = 17; 237 result = 31 * result + mIntent.filterHashCode(); 238 result = 31 * result + mIdent; 239 result = 31 * result + Objects.hashCode(mCurConfig); 240 result = 31 * result + Objects.hashCode(mOverrideConfig); 241 result = 31 * result + mDeviceId; 242 result = 31 * result + Objects.hashCode(mReferrer); 243 result = 31 * result + Objects.hashCode(mProcState); 244 result = 31 * result + getRoughBundleHashCode(mState); 245 result = 31 * result + getRoughBundleHashCode(mPersistentState); 246 result = 31 * result + Objects.hashCode(mPendingResults); 247 result = 31 * result + Objects.hashCode(mPendingNewIntents); 248 result = 31 * result + (mActivityOptions != null ? 1 : 0); 249 result = 31 * result + (mIsForward ? 1 : 0); 250 result = 31 * result + Objects.hashCode(mProfilerInfo); 251 result = 31 * result + Objects.hashCode(mAssistToken); 252 result = 31 * result + Objects.hashCode(mShareableActivityToken); 253 result = 31 * result + Objects.hashCode(mTaskFragmentToken); 254 return result; 255 } 256 activityInfoEqual(ActivityInfo other)257 private boolean activityInfoEqual(ActivityInfo other) { 258 if (mInfo == null) { 259 return other == null; 260 } 261 return other != null && mInfo.flags == other.flags 262 && mInfo.getMaxAspectRatio() == other.getMaxAspectRatio() 263 && Objects.equals(mInfo.launchToken, other.launchToken) 264 && Objects.equals(mInfo.getComponentName(), other.getComponentName()); 265 } 266 267 /** 268 * This method may be used to compare a parceled item with another unparceled item, and the 269 * parceled bundle may contain customized class that will raise BadParcelableException when 270 * unparceling if a customized class loader is not set to the bundle. So the hash code is 271 * simply determined by the bundle is empty or not. 272 */ getRoughBundleHashCode(BaseBundle bundle)273 private static int getRoughBundleHashCode(BaseBundle bundle) { 274 return (bundle == null || bundle.isDefinitelyEmpty()) ? 0 : 1; 275 } 276 277 /** Compares the bundles without unparceling them (avoid BadParcelableException). */ areBundlesEqualRoughly(BaseBundle a, BaseBundle b)278 private static boolean areBundlesEqualRoughly(BaseBundle a, BaseBundle b) { 279 return getRoughBundleHashCode(a) == getRoughBundleHashCode(b); 280 } 281 282 @Override toString()283 public String toString() { 284 return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo 285 + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig 286 + ",deviceId=" + mDeviceId + ",referrer=" + mReferrer + ",procState=" + mProcState 287 + ",state=" + mState + ",persistentState=" + mPersistentState 288 + ",pendingResults=" + mPendingResults + ",pendingNewIntents=" + mPendingNewIntents 289 + ",options=" + mActivityOptions + ",profilerInfo=" + mProfilerInfo 290 + ",assistToken=" + mAssistToken + ",shareableActivityToken=" 291 + mShareableActivityToken + "}"; 292 } 293 294 // 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, int deviceId, 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)295 private static void setValues(LaunchActivityItem instance, Intent intent, int ident, 296 ActivityInfo info, Configuration curConfig, Configuration overrideConfig, int deviceId, 297 String referrer, IVoiceInteractor voiceInteractor, 298 int procState, Bundle state, PersistableBundle persistentState, 299 List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, 300 ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, 301 IBinder assistToken, IActivityClientController activityClientController, 302 IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken) { 303 instance.mIntent = intent; 304 instance.mIdent = ident; 305 instance.mInfo = info; 306 instance.mCurConfig = curConfig; 307 instance.mOverrideConfig = overrideConfig; 308 instance.mDeviceId = deviceId; 309 instance.mReferrer = referrer; 310 instance.mVoiceInteractor = voiceInteractor; 311 instance.mProcState = procState; 312 instance.mState = state; 313 instance.mPersistentState = persistentState; 314 instance.mPendingResults = pendingResults; 315 instance.mPendingNewIntents = pendingNewIntents; 316 instance.mActivityOptions = activityOptions; 317 instance.mIsForward = isForward; 318 instance.mProfilerInfo = profilerInfo; 319 instance.mAssistToken = assistToken; 320 instance.mActivityClientController = activityClientController; 321 instance.mShareableActivityToken = shareableActivityToken; 322 instance.mLaunchedFromBubble = launchedFromBubble; 323 instance.mTaskFragmentToken = taskFragmentToken; 324 } 325 } 326