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.app.ActivityThread.ActivityClientRecord;
22 import android.app.ClientTransactionHandler;
23 import android.app.ProfilerInfo;
24 import android.app.ResultInfo;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.Intent;
27 import android.content.pm.ActivityInfo;
28 import android.content.res.CompatibilityInfo;
29 import android.content.res.Configuration;
30 import android.os.BaseBundle;
31 import android.os.Bundle;
32 import android.os.IBinder;
33 import android.os.Parcel;
34 import android.os.PersistableBundle;
35 import android.os.Trace;
36 
37 import com.android.internal.app.IVoiceInteractor;
38 import com.android.internal.content.ReferrerIntent;
39 
40 import java.util.List;
41 import java.util.Objects;
42 
43 /**
44  * Request to launch an activity.
45  * @hide
46  */
47 public class LaunchActivityItem extends ClientTransactionItem {
48 
49     @UnsupportedAppUsage
50     private Intent mIntent;
51     private int mIdent;
52     @UnsupportedAppUsage
53     private ActivityInfo mInfo;
54     private Configuration mCurConfig;
55     private Configuration mOverrideConfig;
56     private CompatibilityInfo mCompatInfo;
57     private String mReferrer;
58     private IVoiceInteractor mVoiceInteractor;
59     private int mProcState;
60     private Bundle mState;
61     private PersistableBundle mPersistentState;
62     private List<ResultInfo> mPendingResults;
63     private List<ReferrerIntent> mPendingNewIntents;
64     private boolean mIsForward;
65     private ProfilerInfo mProfilerInfo;
66     private IBinder mAssistToken;
67 
68     @Override
preExecute(ClientTransactionHandler client, IBinder token)69     public void preExecute(ClientTransactionHandler client, IBinder token) {
70         client.countLaunchingActivities(1);
71         client.updateProcessState(mProcState, false);
72         client.updatePendingConfiguration(mCurConfig);
73     }
74 
75     @Override
execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)76     public void execute(ClientTransactionHandler client, IBinder token,
77             PendingTransactionActions pendingActions) {
78         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
79         ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
80                 mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
81                 mPendingResults, mPendingNewIntents, mIsForward,
82                 mProfilerInfo, client, mAssistToken);
83         client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
84         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
85     }
86 
87     @Override
postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)88     public void postExecute(ClientTransactionHandler client, IBinder token,
89             PendingTransactionActions pendingActions) {
90         client.countLaunchingActivities(-1);
91     }
92 
93 
94     // ObjectPoolItem implementation
95 
LaunchActivityItem()96     private LaunchActivityItem() {}
97 
98     /** 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, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken)99     public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info,
100             Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo,
101             String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
102             PersistableBundle persistentState, List<ResultInfo> pendingResults,
103             List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo,
104             IBinder assistToken) {
105         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
106         if (instance == null) {
107             instance = new LaunchActivityItem();
108         }
109         setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
110                 voiceInteractor, procState, state, persistentState, pendingResults,
111                 pendingNewIntents, isForward, profilerInfo, assistToken);
112 
113         return instance;
114     }
115 
116     @Override
recycle()117     public void recycle() {
118         setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
119                 false, null, null);
120         ObjectPool.recycle(this);
121     }
122 
123 
124     // Parcelable implementation
125 
126     /** Write from Parcel. */
127     @Override
writeToParcel(Parcel dest, int flags)128     public void writeToParcel(Parcel dest, int flags) {
129         dest.writeTypedObject(mIntent, flags);
130         dest.writeInt(mIdent);
131         dest.writeTypedObject(mInfo, flags);
132         dest.writeTypedObject(mCurConfig, flags);
133         dest.writeTypedObject(mOverrideConfig, flags);
134         dest.writeTypedObject(mCompatInfo, flags);
135         dest.writeString(mReferrer);
136         dest.writeStrongInterface(mVoiceInteractor);
137         dest.writeInt(mProcState);
138         dest.writeBundle(mState);
139         dest.writePersistableBundle(mPersistentState);
140         dest.writeTypedList(mPendingResults, flags);
141         dest.writeTypedList(mPendingNewIntents, flags);
142         dest.writeBoolean(mIsForward);
143         dest.writeTypedObject(mProfilerInfo, flags);
144         dest.writeStrongBinder(mAssistToken);
145     }
146 
147     /** Read from Parcel. */
LaunchActivityItem(Parcel in)148     private LaunchActivityItem(Parcel in) {
149         setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(),
150                 in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR),
151                 in.readTypedObject(Configuration.CREATOR),
152                 in.readTypedObject(CompatibilityInfo.CREATOR), in.readString(),
153                 IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(),
154                 in.readBundle(getClass().getClassLoader()),
155                 in.readPersistableBundle(getClass().getClassLoader()),
156                 in.createTypedArrayList(ResultInfo.CREATOR),
157                 in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(),
158                 in.readTypedObject(ProfilerInfo.CREATOR),
159                 in.readStrongBinder());
160     }
161 
162     public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR =
163             new Creator<LaunchActivityItem>() {
164         public LaunchActivityItem createFromParcel(Parcel in) {
165             return new LaunchActivityItem(in);
166         }
167 
168         public LaunchActivityItem[] newArray(int size) {
169             return new LaunchActivityItem[size];
170         }
171     };
172 
173     @Override
equals(Object o)174     public boolean equals(Object o) {
175         if (this == o) {
176             return true;
177         }
178         if (o == null || getClass() != o.getClass()) {
179             return false;
180         }
181         final LaunchActivityItem other = (LaunchActivityItem) o;
182         final boolean intentsEqual = (mIntent == null && other.mIntent == null)
183                 || (mIntent != null && mIntent.filterEquals(other.mIntent));
184         return intentsEqual && mIdent == other.mIdent
185                 && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig)
186                 && Objects.equals(mOverrideConfig, other.mOverrideConfig)
187                 && Objects.equals(mCompatInfo, other.mCompatInfo)
188                 && Objects.equals(mReferrer, other.mReferrer)
189                 && mProcState == other.mProcState && areBundlesEqual(mState, other.mState)
190                 && areBundlesEqual(mPersistentState, other.mPersistentState)
191                 && Objects.equals(mPendingResults, other.mPendingResults)
192                 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
193                 && mIsForward == other.mIsForward
194                 && Objects.equals(mProfilerInfo, other.mProfilerInfo)
195                 && Objects.equals(mAssistToken, other.mAssistToken);
196     }
197 
198     @Override
hashCode()199     public int hashCode() {
200         int result = 17;
201         result = 31 * result + mIntent.filterHashCode();
202         result = 31 * result + mIdent;
203         result = 31 * result + Objects.hashCode(mCurConfig);
204         result = 31 * result + Objects.hashCode(mOverrideConfig);
205         result = 31 * result + Objects.hashCode(mCompatInfo);
206         result = 31 * result + Objects.hashCode(mReferrer);
207         result = 31 * result + Objects.hashCode(mProcState);
208         result = 31 * result + (mState != null ? mState.size() : 0);
209         result = 31 * result + (mPersistentState != null ? mPersistentState.size() : 0);
210         result = 31 * result + Objects.hashCode(mPendingResults);
211         result = 31 * result + Objects.hashCode(mPendingNewIntents);
212         result = 31 * result + (mIsForward ? 1 : 0);
213         result = 31 * result + Objects.hashCode(mProfilerInfo);
214         result = 31 * result + Objects.hashCode(mAssistToken);
215         return result;
216     }
217 
activityInfoEqual(ActivityInfo other)218     private boolean activityInfoEqual(ActivityInfo other) {
219         if (mInfo == null) {
220             return other == null;
221         }
222         return other != null && mInfo.flags == other.flags
223                 && mInfo.maxAspectRatio == other.maxAspectRatio
224                 && Objects.equals(mInfo.launchToken, other.launchToken)
225                 && Objects.equals(mInfo.getComponentName(), other.getComponentName());
226     }
227 
areBundlesEqual(BaseBundle extras, BaseBundle newExtras)228     private static boolean areBundlesEqual(BaseBundle extras, BaseBundle newExtras) {
229         if (extras == null || newExtras == null) {
230             return extras == newExtras;
231         }
232 
233         if (extras.size() != newExtras.size()) {
234             return false;
235         }
236 
237         for (String key : extras.keySet()) {
238             if (key != null) {
239                 final Object value = extras.get(key);
240                 final Object newValue = newExtras.get(key);
241                 if (!Objects.equals(value, newValue)) {
242                     return false;
243                 }
244             }
245         }
246         return true;
247     }
248 
249     @Override
toString()250     public String toString() {
251         return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo
252                 + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig
253                 + ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
254                 + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
255                 + ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo
256                 + " assistToken=" + mAssistToken
257                 + "}";
258     }
259 
260     // 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, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken)261     private static void setValues(LaunchActivityItem instance, Intent intent, int ident,
262             ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
263             CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
264             int procState, Bundle state, PersistableBundle persistentState,
265             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
266             boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken) {
267         instance.mIntent = intent;
268         instance.mIdent = ident;
269         instance.mInfo = info;
270         instance.mCurConfig = curConfig;
271         instance.mOverrideConfig = overrideConfig;
272         instance.mCompatInfo = compatInfo;
273         instance.mReferrer = referrer;
274         instance.mVoiceInteractor = voiceInteractor;
275         instance.mProcState = procState;
276         instance.mState = state;
277         instance.mPersistentState = persistentState;
278         instance.mPendingResults = pendingResults;
279         instance.mPendingNewIntents = pendingNewIntents;
280         instance.mIsForward = isForward;
281         instance.mProfilerInfo = profilerInfo;
282         instance.mAssistToken = assistToken;
283     }
284 }
285