blob: b08e5973faa26a141f6bac1c156edb755d75a444 [file] [log] [blame]
Andrii Kulian446e8242017-10-26 15:17:29 -07001/*
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
17package android.app.servertransaction;
18
Andrii Kulian88e05cb2017-12-05 17:21:10 -080019import android.annotation.Nullable;
Mathew Inwood98e9ad12018-08-30 13:11:50 +010020import android.annotation.UnsupportedAppUsage;
Andrii Kulian6b9d3a12017-11-16 14:36:36 -080021import android.app.ClientTransactionHandler;
Andrii Kulian446e8242017-10-26 15:17:29 -070022import android.app.IApplicationThread;
23import android.os.IBinder;
24import android.os.Parcel;
25import android.os.Parcelable;
26import android.os.RemoteException;
27
Bryce Lee0bd8d422018-01-09 09:45:57 -080028import com.android.internal.annotations.VisibleForTesting;
29
Andrii Kuliand56ed0c2018-06-14 12:22:18 -070030import java.io.PrintWriter;
Andrii Kulian446e8242017-10-26 15:17:29 -070031import java.util.ArrayList;
32import java.util.List;
Andrii Kulian6b9d3a12017-11-16 14:36:36 -080033import java.util.Objects;
Andrii Kulian446e8242017-10-26 15:17:29 -070034
35/**
36 * A container that holds a sequence of messages, which may be sent to a client.
37 * This includes a list of callbacks and a final lifecycle state.
38 *
39 * @see com.android.server.am.ClientLifecycleManager
40 * @see ClientTransactionItem
41 * @see ActivityLifecycleItem
42 * @hide
43 */
Andrii Kulian9c5ea9c2017-12-07 09:31:01 -080044public class ClientTransaction implements Parcelable, ObjectPoolItem {
Andrii Kulian446e8242017-10-26 15:17:29 -070045
46 /** A list of individual callbacks to a client. */
Mathew Inwood98e9ad12018-08-30 13:11:50 +010047 @UnsupportedAppUsage
Andrii Kulian446e8242017-10-26 15:17:29 -070048 private List<ClientTransactionItem> mActivityCallbacks;
49
50 /**
51 * Final lifecycle state in which the client activity should be after the transaction is
52 * executed.
53 */
54 private ActivityLifecycleItem mLifecycleStateRequest;
55
56 /** Target client. */
57 private IApplicationThread mClient;
58
59 /** Target client activity. Might be null if the entire transaction is targeting an app. */
60 private IBinder mActivityToken;
61
Andrii Kulian04470682018-01-10 15:32:31 -080062 /** Get the target client of the transaction. */
63 public IApplicationThread getClient() {
64 return mClient;
65 }
66
Andrii Kulian446e8242017-10-26 15:17:29 -070067 /**
68 * Add a message to the end of the sequence of callbacks.
69 * @param activityCallback A single message that can contain a lifecycle request/callback.
70 */
71 public void addCallback(ClientTransactionItem activityCallback) {
72 if (mActivityCallbacks == null) {
73 mActivityCallbacks = new ArrayList<>();
74 }
75 mActivityCallbacks.add(activityCallback);
76 }
77
Andrii Kulian88e05cb2017-12-05 17:21:10 -080078 /** Get the list of callbacks. */
79 @Nullable
Mathew Inwood98e9ad12018-08-30 13:11:50 +010080 @UnsupportedAppUsage
Andrii Kulian88e05cb2017-12-05 17:21:10 -080081 List<ClientTransactionItem> getCallbacks() {
82 return mActivityCallbacks;
83 }
84
85 /** Get the target activity. */
86 @Nullable
Mathew Inwood98e9ad12018-08-30 13:11:50 +010087 @UnsupportedAppUsage
Andrii Kulian88e05cb2017-12-05 17:21:10 -080088 public IBinder getActivityToken() {
89 return mActivityToken;
90 }
91
92 /** Get the target state lifecycle request. */
Bryce Lee0bd8d422018-01-09 09:45:57 -080093 @VisibleForTesting
Mathew Inwood98e9ad12018-08-30 13:11:50 +010094 @UnsupportedAppUsage
Bryce Lee0bd8d422018-01-09 09:45:57 -080095 public ActivityLifecycleItem getLifecycleStateRequest() {
Andrii Kulian88e05cb2017-12-05 17:21:10 -080096 return mLifecycleStateRequest;
97 }
98
Andrii Kulian446e8242017-10-26 15:17:29 -070099 /**
100 * Set the lifecycle state in which the client should be after executing the transaction.
101 * @param stateRequest A lifecycle request initialized with right parameters.
102 */
103 public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
104 mLifecycleStateRequest = stateRequest;
105 }
106
107 /**
108 * Do what needs to be done while the transaction is being scheduled on the client side.
109 * @param clientTransactionHandler Handler on the client side that will executed all operations
110 * requested by transaction items.
111 */
Andrii Kulian88e05cb2017-12-05 17:21:10 -0800112 public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
Andrii Kulian446e8242017-10-26 15:17:29 -0700113 if (mActivityCallbacks != null) {
114 final int size = mActivityCallbacks.size();
115 for (int i = 0; i < size; ++i) {
Andrii Kulian88e05cb2017-12-05 17:21:10 -0800116 mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
Andrii Kulian446e8242017-10-26 15:17:29 -0700117 }
118 }
119 if (mLifecycleStateRequest != null) {
Andrii Kulian88e05cb2017-12-05 17:21:10 -0800120 mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken);
Andrii Kulian446e8242017-10-26 15:17:29 -0700121 }
122 }
123
124 /**
125 * Schedule the transaction after it was initialized. It will be send to client and all its
126 * individual parts will be applied in the following sequence:
Andrii Kulian88e05cb2017-12-05 17:21:10 -0800127 * 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work
128 * that needs to be done before actually scheduling the transaction for callbacks and
129 * lifecycle state request.
Andrii Kulian446e8242017-10-26 15:17:29 -0700130 * 2. The transaction message is scheduled.
Andrii Kulian88e05cb2017-12-05 17:21:10 -0800131 * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
132 * all callbacks and necessary lifecycle transitions.
Andrii Kulian446e8242017-10-26 15:17:29 -0700133 */
134 public void schedule() throws RemoteException {
135 mClient.scheduleTransaction(this);
136 }
137
138
Andrii Kulian9c5ea9c2017-12-07 09:31:01 -0800139 // ObjectPoolItem implementation
140
141 private ClientTransaction() {}
142
143 /** Obtain an instance initialized with provided params. */
144 public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
145 ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
146 if (instance == null) {
147 instance = new ClientTransaction();
148 }
149 instance.mClient = client;
150 instance.mActivityToken = activityToken;
151
152 return instance;
153 }
154
155 @Override
156 public void recycle() {
157 if (mActivityCallbacks != null) {
158 int size = mActivityCallbacks.size();
159 for (int i = 0; i < size; i++) {
160 mActivityCallbacks.get(i).recycle();
161 }
162 mActivityCallbacks.clear();
163 }
164 if (mLifecycleStateRequest != null) {
165 mLifecycleStateRequest.recycle();
166 mLifecycleStateRequest = null;
167 }
168 mClient = null;
169 mActivityToken = null;
170 ObjectPool.recycle(this);
171 }
172
Andrii Kulian446e8242017-10-26 15:17:29 -0700173 // Parcelable implementation
174
175 /** Write to Parcel. */
176 @Override
177 public void writeToParcel(Parcel dest, int flags) {
178 dest.writeStrongBinder(mClient.asBinder());
179 final boolean writeActivityToken = mActivityToken != null;
180 dest.writeBoolean(writeActivityToken);
181 if (writeActivityToken) {
182 dest.writeStrongBinder(mActivityToken);
183 }
184 dest.writeParcelable(mLifecycleStateRequest, flags);
185 final boolean writeActivityCallbacks = mActivityCallbacks != null;
186 dest.writeBoolean(writeActivityCallbacks);
187 if (writeActivityCallbacks) {
188 dest.writeParcelableList(mActivityCallbacks, flags);
189 }
190 }
191
192 /** Read from Parcel. */
193 private ClientTransaction(Parcel in) {
194 mClient = (IApplicationThread) in.readStrongBinder();
195 final boolean readActivityToken = in.readBoolean();
196 if (readActivityToken) {
197 mActivityToken = in.readStrongBinder();
198 }
199 mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader());
200 final boolean readActivityCallbacks = in.readBoolean();
201 if (readActivityCallbacks) {
202 mActivityCallbacks = new ArrayList<>();
203 in.readParcelableList(mActivityCallbacks, getClass().getClassLoader());
204 }
205 }
206
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700207 public static final @android.annotation.NonNull Creator<ClientTransaction> CREATOR =
Andrii Kulian446e8242017-10-26 15:17:29 -0700208 new Creator<ClientTransaction>() {
209 public ClientTransaction createFromParcel(Parcel in) {
210 return new ClientTransaction(in);
211 }
212
213 public ClientTransaction[] newArray(int size) {
214 return new ClientTransaction[size];
215 }
216 };
217
218 @Override
219 public int describeContents() {
220 return 0;
221 }
Andrii Kulian6b9d3a12017-11-16 14:36:36 -0800222
223 @Override
224 public boolean equals(Object o) {
225 if (this == o) {
226 return true;
227 }
228 if (o == null || getClass() != o.getClass()) {
229 return false;
230 }
231 final ClientTransaction other = (ClientTransaction) o;
232 return Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
233 && Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest)
234 && mClient == other.mClient
235 && mActivityToken == other.mActivityToken;
236 }
237
238 @Override
239 public int hashCode() {
240 int result = 17;
241 result = 31 * result + Objects.hashCode(mActivityCallbacks);
242 result = 31 * result + Objects.hashCode(mLifecycleStateRequest);
243 return result;
244 }
Andrii Kuliand56ed0c2018-06-14 12:22:18 -0700245
246 /** Dump transaction items callback items and final lifecycle state request. */
247 public void dump(String prefix, PrintWriter pw) {
248 pw.append(prefix).println("ClientTransaction{");
249 pw.append(prefix).print(" callbacks=[");
250 final int size = mActivityCallbacks != null ? mActivityCallbacks.size() : 0;
251 if (size > 0) {
252 pw.println();
253 for (int i = 0; i < size; i++) {
254 pw.append(prefix).append(" ").println(mActivityCallbacks.get(i).toString());
255 }
256 pw.append(prefix).println(" ]");
257 } else {
258 pw.println("]");
259 }
260 pw.append(prefix).append(" stateRequest=").println(mLifecycleStateRequest != null
261 ? mLifecycleStateRequest.toString() : null);
262 pw.append(prefix).println("}");
263 }
Andrii Kulian446e8242017-10-26 15:17:29 -0700264}