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