1 /*
2  * Copyright (C) 2022 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.car.occupantconnection;
18 
19 
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.os.IBinder;
24 import android.os.Parcel;
25 
26 import com.android.car.internal.LargeParcelableBase;
27 
28 import java.util.Arrays;
29 import java.util.Objects;
30 
31 /**
32  * A payload sent between client apps that have the same package name but run in different occupant
33  * zones in the car.
34  * <p>
35  * The payload either contains a byte array, or a Binder object. In the former case, the payload
36  * can be sent to any occupant zone in the car, no matter whether it runs on the same Android
37  * instance or another Android instance. In the latter case, the payload can be only sent to another
38  * occupant zone on the same Android instance; otherwise, the receiver app can still receive the
39  * payload, but the Binder object of the payload will be {@code null}.
40  * <p>
41  * After establishing a connection to the receiver client, the sender client can send a payload via
42  * {@link CarOccupantConnectionManager#sendPayload}. The receiver service in the receiver client
43  * will receive the payload via {@link AbstractReceiverService#onPayloadReceived}, then dispatch it
44  * to the proper receiver endpoint(s).
45  * <p>
46  * The sender client can put the receiver endpoint ID in the payload so that the receiver service
47  * knows which receiver endpoint(s) to dispatch the payload to.
48  *
49  * @hide
50  */
51 @SystemApi
52 public final class Payload extends LargeParcelableBase {
53 
54     @Nullable
55     private byte[] mBytes;
56 
57     @Nullable
58     private IBinder mBinder;
59 
Payload(@onNull byte[] bytes)60     public Payload(@NonNull byte[] bytes) {
61         Objects.requireNonNull(bytes, "bytes cannot be null");
62         this.mBytes = bytes.clone();
63     }
64 
Payload(@onNull Parcel in)65     private Payload(@NonNull Parcel in) {
66         super(in);
67     }
68 
69     /**
70      * Creates a Payload that holds an IBinder object. This type of Payload
71      * can only be sent between occupant zones running on the same Android instance.
72      */
Payload(@onNull IBinder binder)73     public Payload(@NonNull IBinder binder) {
74         this.mBinder = Objects.requireNonNull(binder, "binder cannot be null");
75     }
76 
77     /** Returns a reference to the byte array of the payload. */
78     @Nullable
getBytes()79     public byte[] getBytes() {
80         return mBytes;
81     }
82 
83     /** Returns a reference to the Binder object of the payload. */
84     @Nullable
getBinder()85     public IBinder getBinder() {
86         return mBinder;
87     }
88 
89     /**
90      * {@inheritDoc}
91      */
92     @Override
equals(Object o)93     public boolean equals(Object o) {
94         if (this == o) {
95             return true;
96         }
97         if (o instanceof Payload) {
98             Payload other = (Payload) o;
99             if (containsBinder()) {
100                 return mBinder == other.mBinder;
101             } else {
102                 return Arrays.equals(mBytes, other.mBytes);
103             }
104         }
105         return false;
106     }
107 
108     /**
109      * {@inheritDoc}
110      */
111     @Override
hashCode()112     public int hashCode() {
113         if (containsBinder()) {
114             return Objects.hashCode(mBinder);
115         } else {
116             return Arrays.hashCode(mBytes);
117         }
118     }
119 
120     @NonNull
121     public static final Creator<Payload> CREATOR = new Creator<>() {
122         /**
123          * {@inheritDoc}
124          */
125         @Override
126         public Payload createFromParcel(Parcel in) {
127             return new Payload(in);
128         }
129 
130         /**
131          * {@inheritDoc}
132          */
133         @Override
134         public Payload[] newArray(int size) {
135             return new Payload[size];
136         }
137     };
138 
139     /**
140      * {@inheritDoc}
141      */
142     @Override
describeContents()143     public int describeContents() {
144         return 0;
145     }
146 
147     /** Writes this {@link Payload} into the given {@link Parcel}. */
148     @Override
serialize(@onNull Parcel dest, int flags)149     public void serialize(@NonNull Parcel dest, int flags) {
150         dest.writeBoolean(containsBinder());
151         // writeByteArray() uses shared memory, so it cannot be called with writeStrongBinder()
152         if (containsBinder()) {
153             dest.writeStrongBinder(mBinder);
154         } else {
155             dest.writeByteArray(mBytes);
156         }
157     }
158 
159     /** Writes {@code null} {@link Payload} to the given {@link Parcel}. */
160     @Override
serializeNullPayload(@onNull Parcel dest)161     public void serializeNullPayload(@NonNull Parcel dest) {
162         dest.writeBoolean(false);
163         dest.writeByteArray(null);
164     }
165 
166     /** Reads a {@link Payload} from the given {@link Parcel}. */
167     @Override
deserialize(@onNull Parcel src)168     public void deserialize(@NonNull Parcel src) {
169         if (src.readBoolean()) {
170             mBinder = src.readStrongBinder();
171             mBytes = null;
172         } else {
173             mBytes = src.createByteArray();
174             mBinder = null;
175         }
176     }
177 
178     /**
179      * This function returns {@code true} if the payload contains a Binder object, and
180      * {@code false} if it contains a byte array.
181      */
containsBinder()182     private boolean containsBinder() {
183         return mBinder != null;
184     }
185 
186     // The method needs to be overridden for a CtsSystemApiAnnotationTestCases. Ideally test should
187     // be fixed, but it is an edge case, so these methods are overridden. It is happening because
188     // LargeParcelableBase is hidden class but it implements parcelable and closeable which are
189     // public APIs. So the test is not able to find these methods in payload.java and complains.
190     // More details in b/275738385
191     @Override
close()192     public void close() {
193         super.close();
194     }
195 
196     @Override
writeToParcel(@onNull Parcel dest, int flags)197     public void writeToParcel(@NonNull Parcel dest, int flags) {
198         super.writeToParcel(dest, flags);
199     }
200 }
201