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