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.os.IBinder; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.os.RemoteException; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Objects; 32 33 /** 34 * A container that holds a sequence of messages, which may be sent to a client. 35 * This includes a list of callbacks and a final lifecycle state. 36 * 37 * @see com.android.server.am.ClientLifecycleManager 38 * @see ClientTransactionItem 39 * @see ActivityLifecycleItem 40 * @hide 41 */ 42 public class ClientTransaction implements Parcelable, ObjectPoolItem { 43 44 /** A list of individual callbacks to a client. */ 45 private List<ClientTransactionItem> mActivityCallbacks; 46 47 /** 48 * Final lifecycle state in which the client activity should be after the transaction is 49 * executed. 50 */ 51 private ActivityLifecycleItem mLifecycleStateRequest; 52 53 /** Target client. */ 54 private IApplicationThread mClient; 55 56 /** Target client activity. Might be null if the entire transaction is targeting an app. */ 57 private IBinder mActivityToken; 58 59 /** Get the target client of the transaction. */ getClient()60 public IApplicationThread getClient() { 61 return mClient; 62 } 63 64 /** 65 * Add a message to the end of the sequence of callbacks. 66 * @param activityCallback A single message that can contain a lifecycle request/callback. 67 */ addCallback(ClientTransactionItem activityCallback)68 public void addCallback(ClientTransactionItem activityCallback) { 69 if (mActivityCallbacks == null) { 70 mActivityCallbacks = new ArrayList<>(); 71 } 72 mActivityCallbacks.add(activityCallback); 73 } 74 75 /** Get the list of callbacks. */ 76 @Nullable getCallbacks()77 List<ClientTransactionItem> getCallbacks() { 78 return mActivityCallbacks; 79 } 80 81 /** Get the target activity. */ 82 @Nullable getActivityToken()83 public IBinder getActivityToken() { 84 return mActivityToken; 85 } 86 87 /** Get the target state lifecycle request. */ 88 @VisibleForTesting getLifecycleStateRequest()89 public ActivityLifecycleItem getLifecycleStateRequest() { 90 return mLifecycleStateRequest; 91 } 92 93 /** 94 * Set the lifecycle state in which the client should be after executing the transaction. 95 * @param stateRequest A lifecycle request initialized with right parameters. 96 */ setLifecycleStateRequest(ActivityLifecycleItem stateRequest)97 public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) { 98 mLifecycleStateRequest = stateRequest; 99 } 100 101 /** 102 * Do what needs to be done while the transaction is being scheduled on the client side. 103 * @param clientTransactionHandler Handler on the client side that will executed all operations 104 * requested by transaction items. 105 */ preExecute(android.app.ClientTransactionHandler clientTransactionHandler)106 public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) { 107 if (mActivityCallbacks != null) { 108 final int size = mActivityCallbacks.size(); 109 for (int i = 0; i < size; ++i) { 110 mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken); 111 } 112 } 113 if (mLifecycleStateRequest != null) { 114 mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken); 115 } 116 } 117 118 /** 119 * Schedule the transaction after it was initialized. It will be send to client and all its 120 * individual parts will be applied in the following sequence: 121 * 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work 122 * that needs to be done before actually scheduling the transaction for callbacks and 123 * lifecycle state request. 124 * 2. The transaction message is scheduled. 125 * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes 126 * all callbacks and necessary lifecycle transitions. 127 */ schedule()128 public void schedule() throws RemoteException { 129 mClient.scheduleTransaction(this); 130 } 131 132 133 // ObjectPoolItem implementation 134 ClientTransaction()135 private ClientTransaction() {} 136 137 /** Obtain an instance initialized with provided params. */ obtain(IApplicationThread client, IBinder activityToken)138 public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) { 139 ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class); 140 if (instance == null) { 141 instance = new ClientTransaction(); 142 } 143 instance.mClient = client; 144 instance.mActivityToken = activityToken; 145 146 return instance; 147 } 148 149 @Override recycle()150 public void recycle() { 151 if (mActivityCallbacks != null) { 152 int size = mActivityCallbacks.size(); 153 for (int i = 0; i < size; i++) { 154 mActivityCallbacks.get(i).recycle(); 155 } 156 mActivityCallbacks.clear(); 157 } 158 if (mLifecycleStateRequest != null) { 159 mLifecycleStateRequest.recycle(); 160 mLifecycleStateRequest = null; 161 } 162 mClient = null; 163 mActivityToken = null; 164 ObjectPool.recycle(this); 165 } 166 167 168 // Parcelable implementation 169 170 /** Write to Parcel. */ 171 @Override writeToParcel(Parcel dest, int flags)172 public void writeToParcel(Parcel dest, int flags) { 173 dest.writeStrongBinder(mClient.asBinder()); 174 final boolean writeActivityToken = mActivityToken != null; 175 dest.writeBoolean(writeActivityToken); 176 if (writeActivityToken) { 177 dest.writeStrongBinder(mActivityToken); 178 } 179 dest.writeParcelable(mLifecycleStateRequest, flags); 180 final boolean writeActivityCallbacks = mActivityCallbacks != null; 181 dest.writeBoolean(writeActivityCallbacks); 182 if (writeActivityCallbacks) { 183 dest.writeParcelableList(mActivityCallbacks, flags); 184 } 185 } 186 187 /** Read from Parcel. */ ClientTransaction(Parcel in)188 private ClientTransaction(Parcel in) { 189 mClient = (IApplicationThread) in.readStrongBinder(); 190 final boolean readActivityToken = in.readBoolean(); 191 if (readActivityToken) { 192 mActivityToken = in.readStrongBinder(); 193 } 194 mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader()); 195 final boolean readActivityCallbacks = in.readBoolean(); 196 if (readActivityCallbacks) { 197 mActivityCallbacks = new ArrayList<>(); 198 in.readParcelableList(mActivityCallbacks, getClass().getClassLoader()); 199 } 200 } 201 202 public static final Creator<ClientTransaction> CREATOR = 203 new Creator<ClientTransaction>() { 204 public ClientTransaction createFromParcel(Parcel in) { 205 return new ClientTransaction(in); 206 } 207 208 public ClientTransaction[] newArray(int size) { 209 return new ClientTransaction[size]; 210 } 211 }; 212 213 @Override describeContents()214 public int describeContents() { 215 return 0; 216 } 217 218 @Override equals(Object o)219 public boolean equals(Object o) { 220 if (this == o) { 221 return true; 222 } 223 if (o == null || getClass() != o.getClass()) { 224 return false; 225 } 226 final ClientTransaction other = (ClientTransaction) o; 227 return Objects.equals(mActivityCallbacks, other.mActivityCallbacks) 228 && Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest) 229 && mClient == other.mClient 230 && mActivityToken == other.mActivityToken; 231 } 232 233 @Override hashCode()234 public int hashCode() { 235 int result = 17; 236 result = 31 * result + Objects.hashCode(mActivityCallbacks); 237 result = 31 * result + Objects.hashCode(mLifecycleStateRequest); 238 return result; 239 } 240 } 241