• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.annotation.Nullable;
20 import android.app.ClientTransactionHandler;
21 import android.app.IApplicationThread;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.os.IBinder;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.os.RemoteException;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Objects;
34 
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  */
44 public class ClientTransaction implements Parcelable, ObjectPoolItem {
45 
46     /** A list of individual callbacks to a client. */
47     @UnsupportedAppUsage
48     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 
62     /** Get the target client of the transaction. */
getClient()63     public IApplicationThread getClient() {
64         return mClient;
65     }
66 
67     /**
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      */
addCallback(ClientTransactionItem activityCallback)71     public void addCallback(ClientTransactionItem activityCallback) {
72         if (mActivityCallbacks == null) {
73             mActivityCallbacks = new ArrayList<>();
74         }
75         mActivityCallbacks.add(activityCallback);
76     }
77 
78     /** Get the list of callbacks. */
79     @Nullable
80     @VisibleForTesting
81     @UnsupportedAppUsage
getCallbacks()82     public List<ClientTransactionItem> getCallbacks() {
83         return mActivityCallbacks;
84     }
85 
86     /** Get the target activity. */
87     @Nullable
88     @UnsupportedAppUsage
getActivityToken()89     public IBinder getActivityToken() {
90         return mActivityToken;
91     }
92 
93     /** Get the target state lifecycle request. */
94     @VisibleForTesting
95     @UnsupportedAppUsage
getLifecycleStateRequest()96     public ActivityLifecycleItem getLifecycleStateRequest() {
97         return mLifecycleStateRequest;
98     }
99 
100     /**
101      * Set the lifecycle state in which the client should be after executing the transaction.
102      * @param stateRequest A lifecycle request initialized with right parameters.
103      */
setLifecycleStateRequest(ActivityLifecycleItem stateRequest)104     public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
105         mLifecycleStateRequest = stateRequest;
106     }
107 
108     /**
109      * Do what needs to be done while the transaction is being scheduled on the client side.
110      * @param clientTransactionHandler Handler on the client side that will executed all operations
111      *                                 requested by transaction items.
112      */
preExecute(android.app.ClientTransactionHandler clientTransactionHandler)113     public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
114         if (mActivityCallbacks != null) {
115             final int size = mActivityCallbacks.size();
116             for (int i = 0; i < size; ++i) {
117                 mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
118             }
119         }
120         if (mLifecycleStateRequest != null) {
121             mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken);
122         }
123     }
124 
125     /**
126      * Schedule the transaction after it was initialized. It will be send to client and all its
127      * individual parts will be applied in the following sequence:
128      * 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work
129      *    that needs to be done before actually scheduling the transaction for callbacks and
130      *    lifecycle state request.
131      * 2. The transaction message is scheduled.
132      * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
133      *    all callbacks and necessary lifecycle transitions.
134      */
schedule()135     public void schedule() throws RemoteException {
136         mClient.scheduleTransaction(this);
137     }
138 
139 
140     // ObjectPoolItem implementation
141 
ClientTransaction()142     private ClientTransaction() {}
143 
144     /** Obtain an instance initialized with provided params. */
obtain(IApplicationThread client, IBinder activityToken)145     public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
146         ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
147         if (instance == null) {
148             instance = new ClientTransaction();
149         }
150         instance.mClient = client;
151         instance.mActivityToken = activityToken;
152 
153         return instance;
154     }
155 
156     @Override
recycle()157     public void recycle() {
158         if (mActivityCallbacks != null) {
159             int size = mActivityCallbacks.size();
160             for (int i = 0; i < size; i++) {
161                 mActivityCallbacks.get(i).recycle();
162             }
163             mActivityCallbacks.clear();
164         }
165         if (mLifecycleStateRequest != null) {
166             mLifecycleStateRequest.recycle();
167             mLifecycleStateRequest = null;
168         }
169         mClient = null;
170         mActivityToken = null;
171         ObjectPool.recycle(this);
172     }
173 
174     // Parcelable implementation
175 
176     /** Write to Parcel. */
177     @Override
writeToParcel(Parcel dest, int flags)178     public void writeToParcel(Parcel dest, int flags) {
179         dest.writeStrongBinder(mClient.asBinder());
180         final boolean writeActivityToken = mActivityToken != null;
181         dest.writeBoolean(writeActivityToken);
182         if (writeActivityToken) {
183             dest.writeStrongBinder(mActivityToken);
184         }
185         dest.writeParcelable(mLifecycleStateRequest, flags);
186         final boolean writeActivityCallbacks = mActivityCallbacks != null;
187         dest.writeBoolean(writeActivityCallbacks);
188         if (writeActivityCallbacks) {
189             dest.writeParcelableList(mActivityCallbacks, flags);
190         }
191     }
192 
193     /** Read from Parcel. */
ClientTransaction(Parcel in)194     private ClientTransaction(Parcel in) {
195         mClient = (IApplicationThread) in.readStrongBinder();
196         final boolean readActivityToken = in.readBoolean();
197         if (readActivityToken) {
198             mActivityToken = in.readStrongBinder();
199         }
200         mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader());
201         final boolean readActivityCallbacks = in.readBoolean();
202         if (readActivityCallbacks) {
203             mActivityCallbacks = new ArrayList<>();
204             in.readParcelableList(mActivityCallbacks, getClass().getClassLoader());
205         }
206     }
207 
208     public static final @android.annotation.NonNull Creator<ClientTransaction> CREATOR =
209             new Creator<ClientTransaction>() {
210         public ClientTransaction createFromParcel(Parcel in) {
211             return new ClientTransaction(in);
212         }
213 
214         public ClientTransaction[] newArray(int size) {
215             return new ClientTransaction[size];
216         }
217     };
218 
219     @Override
describeContents()220     public int describeContents() {
221         return 0;
222     }
223 
224     @Override
equals(@ullable Object o)225     public boolean equals(@Nullable Object o) {
226         if (this == o) {
227             return true;
228         }
229         if (o == null || getClass() != o.getClass()) {
230             return false;
231         }
232         final ClientTransaction other = (ClientTransaction) o;
233         return Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
234                 && Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest)
235                 && mClient == other.mClient
236                 && mActivityToken == other.mActivityToken;
237     }
238 
239     @Override
hashCode()240     public int hashCode() {
241         int result = 17;
242         result = 31 * result + Objects.hashCode(mActivityCallbacks);
243         result = 31 * result + Objects.hashCode(mLifecycleStateRequest);
244         result = 31 * result + Objects.hashCode(mClient);
245         result = 31 * result + Objects.hashCode(mActivityToken);
246         return result;
247     }
248 
249     /** Dump transaction items callback items and final lifecycle state request. */
dump(String prefix, PrintWriter pw)250     public void dump(String prefix, PrintWriter pw) {
251         pw.append(prefix).println("ClientTransaction{");
252         pw.append(prefix).print("  callbacks=[");
253         final int size = mActivityCallbacks != null ? mActivityCallbacks.size() : 0;
254         if (size > 0) {
255             pw.println();
256             for (int i = 0; i < size; i++) {
257                 pw.append(prefix).append("    ").println(mActivityCallbacks.get(i).toString());
258             }
259             pw.append(prefix).println("  ]");
260         } else {
261             pw.println("]");
262         }
263         pw.append(prefix).append("  stateRequest=").println(mLifecycleStateRequest != null
264                 ? mLifecycleStateRequest.toString() : null);
265         pw.append(prefix).println("}");
266     }
267 }
268