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