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 package android.hardware.location; 17 18 import android.annotation.FlaggedApi; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.chre.flags.Flags; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 26 import libcore.util.HexEncoding; 27 28 import java.util.Arrays; 29 import java.util.Objects; 30 31 /** 32 * A class describing messages send to or from nanoapps through the Context Hub Service. 33 * 34 * The basis of the class is in the IContextHub.hal ContextHubMsg definition. 35 * 36 * @hide 37 */ 38 @SystemApi 39 public final class NanoAppMessage implements Parcelable { 40 private static final int DEBUG_LOG_NUM_BYTES = 16; 41 private long mNanoAppId; 42 private int mMessageType; 43 private byte[] mMessageBody; 44 private boolean mIsBroadcasted; 45 private boolean mIsReliable; 46 private int mMessageSequenceNumber; 47 NanoAppMessage(long nanoAppId, int messageType, byte[] messageBody, boolean broadcasted, boolean isReliable, int messageSequenceNumber)48 private NanoAppMessage(long nanoAppId, int messageType, byte[] messageBody, 49 boolean broadcasted, boolean isReliable, int messageSequenceNumber) { 50 mNanoAppId = nanoAppId; 51 mMessageType = messageType; 52 mMessageBody = messageBody; 53 mIsBroadcasted = broadcasted; 54 mIsReliable = isReliable; 55 mMessageSequenceNumber = messageSequenceNumber; 56 } 57 58 /** 59 * Creates a NanoAppMessage object to send to a nanoapp. 60 * 61 * This factory method can be used to generate a NanoAppMessage object to be used in 62 * the ContextHubClient.sendMessageToNanoApp API. 63 * 64 * @param targetNanoAppId the ID of the nanoapp to send the message to 65 * @param messageType the nanoapp-dependent message type 66 * the value CHRE_MESSAGE_TYPE_RPC (0x7FFFFFF5) is reserved by the 67 * framework for RPC messages 68 * @param messageBody the byte array message contents 69 * 70 * @return the NanoAppMessage object 71 */ createMessageToNanoApp(long targetNanoAppId, int messageType, byte[] messageBody)72 public static NanoAppMessage createMessageToNanoApp(long targetNanoAppId, int messageType, 73 byte[] messageBody) { 74 return new NanoAppMessage(targetNanoAppId, messageType, messageBody, 75 false /* broadcasted */, false /* isReliable */, 0 /* messageSequenceNumber */); 76 } 77 78 /** 79 * Creates a NanoAppMessage object sent from a nanoapp. 80 * 81 * This factory method is intended only to be used by the Context Hub Service when delivering 82 * messages from a nanoapp to clients. 83 * 84 * @param sourceNanoAppId the ID of the nanoapp that the message was sent from 85 * @param messageType the nanoapp-dependent message type 86 * @param messageBody the byte array message contents 87 * @param broadcasted {@code true} if the message was broadcasted, {@code false} otherwise 88 * 89 * @return the NanoAppMessage object 90 */ createMessageFromNanoApp(long sourceNanoAppId, int messageType, byte[] messageBody, boolean broadcasted)91 public static NanoAppMessage createMessageFromNanoApp(long sourceNanoAppId, int messageType, 92 byte[] messageBody, boolean broadcasted) { 93 return new NanoAppMessage(sourceNanoAppId, messageType, messageBody, broadcasted, 94 false /* isReliable */, 0 /* messageSequenceNumber */); 95 } 96 97 /** 98 * Creates a NanoAppMessage object sent from a nanoapp. 99 * 100 * <p>This factory method is intended only to be used by the Context Hub Service when delivering 101 * messages from a nanoapp to clients. 102 * 103 * @param sourceNanoAppId the ID of the nanoapp that the message was sent from 104 * @param messageType the nanoapp-dependent message type 105 * @param messageBody the byte array message contents 106 * @param broadcasted {@code true} if the message was broadcasted, {@code false} otherwise 107 * @param isReliable if the NanoAppMessage is reliable 108 * @param messageSequenceNumber the message sequence number of the NanoAppMessage 109 * @return the NanoAppMessage object 110 */ createMessageFromNanoApp( long sourceNanoAppId, int messageType, @NonNull byte[] messageBody, boolean broadcasted, boolean isReliable, int messageSequenceNumber)111 public static @NonNull NanoAppMessage createMessageFromNanoApp( 112 long sourceNanoAppId, 113 int messageType, 114 @NonNull byte[] messageBody, 115 boolean broadcasted, 116 boolean isReliable, 117 int messageSequenceNumber) { 118 return new NanoAppMessage(sourceNanoAppId, messageType, messageBody, broadcasted, 119 isReliable, messageSequenceNumber); 120 } 121 122 /** 123 * @return the ID of the source or destination nanoapp 124 */ getNanoAppId()125 public long getNanoAppId() { 126 return mNanoAppId; 127 } 128 129 /** 130 * @return the type of the message that is nanoapp-dependent 131 */ getMessageType()132 public int getMessageType() { 133 return mMessageType; 134 } 135 136 /** 137 * @return the byte array contents of the message 138 */ getMessageBody()139 public byte[] getMessageBody() { 140 return mMessageBody; 141 } 142 143 /** 144 * @return {@code true} if the message is broadcasted, {@code false} otherwise 145 */ isBroadcastMessage()146 public boolean isBroadcastMessage() { 147 return mIsBroadcasted; 148 } 149 150 /** 151 * Returns if the message is reliable. The default value is {@code false} 152 * 153 * @return {@code true} if the message is reliable, {@code false} otherwise 154 */ isReliable()155 public boolean isReliable() { 156 return mIsReliable; 157 } 158 159 /** 160 * Returns the message sequence number. The default value is 0 161 * 162 * @return the message sequence number of the message 163 */ getMessageSequenceNumber()164 public int getMessageSequenceNumber() { 165 return mMessageSequenceNumber; 166 } 167 168 /** 169 * Sets the isReliable field of the message 170 * 171 * @hide 172 */ setIsReliable(boolean isReliable)173 public void setIsReliable(boolean isReliable) { 174 mIsReliable = isReliable; 175 } 176 177 /** 178 * Sets the message sequence number of the message 179 * 180 * @hide 181 */ setMessageSequenceNumber(int messageSequenceNumber)182 public void setMessageSequenceNumber(int messageSequenceNumber) { 183 mMessageSequenceNumber = messageSequenceNumber; 184 } 185 NanoAppMessage(Parcel in)186 private NanoAppMessage(Parcel in) { 187 mNanoAppId = in.readLong(); 188 mIsBroadcasted = (in.readInt() == 1); 189 mMessageType = in.readInt(); 190 191 int msgSize = in.readInt(); 192 mMessageBody = new byte[msgSize]; 193 in.readByteArray(mMessageBody); 194 195 mIsReliable = (in.readInt() == 1); 196 mMessageSequenceNumber = in.readInt(); 197 } 198 199 @Override describeContents()200 public int describeContents() { 201 return 0; 202 } 203 204 @Override writeToParcel(Parcel out, int flags)205 public void writeToParcel(Parcel out, int flags) { 206 out.writeLong(mNanoAppId); 207 out.writeInt(mIsBroadcasted ? 1 : 0); 208 out.writeInt(mMessageType); 209 210 out.writeInt(mMessageBody.length); 211 out.writeByteArray(mMessageBody); 212 213 out.writeInt(mIsReliable ? 1 : 0); 214 out.writeInt(mMessageSequenceNumber); 215 } 216 217 public static final @NonNull Creator<NanoAppMessage> CREATOR = 218 new Creator<NanoAppMessage>() { 219 @Override 220 public NanoAppMessage createFromParcel(Parcel in) { 221 return new NanoAppMessage(in); 222 } 223 224 @Override 225 public NanoAppMessage[] newArray(int size) { 226 return new NanoAppMessage[size]; 227 } 228 }; 229 230 @NonNull 231 @Override toString()232 public String toString() { 233 int length = mMessageBody.length; 234 235 StringBuilder out = new StringBuilder(); 236 out.append( "NanoAppMessage[type = "); 237 out.append(mMessageType); 238 out.append(", length = "); 239 out.append(mMessageBody.length); 240 out.append(" bytes, "); 241 out.append(mIsBroadcasted ? "broadcast" : "unicast"); 242 out.append(", nanoapp = 0x"); 243 out.append(Long.toHexString(mNanoAppId)); 244 out.append(", isReliable = "); 245 out.append(mIsReliable ? "true" : "false"); 246 out.append(", messageSequenceNumber = "); 247 out.append(mMessageSequenceNumber); 248 out.append("]("); 249 250 if (length > 0) { 251 out.append("data = 0x"); 252 } 253 for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) { 254 out.append(HexEncoding.encodeToString(mMessageBody[i], 255 true /* upperCase */)); 256 257 if ((i + 1) % 4 == 0) { 258 out.append(" "); 259 } 260 } 261 if (length > DEBUG_LOG_NUM_BYTES) { 262 out.append("..."); 263 } 264 out.append(")"); 265 266 return out.toString(); 267 } 268 269 @Override equals(@ullable Object object)270 public boolean equals(@Nullable Object object) { 271 if (object == this) { 272 return true; 273 } 274 275 boolean isEqual = false; 276 if (object instanceof NanoAppMessage) { 277 NanoAppMessage other = (NanoAppMessage) object; 278 isEqual = (other.getNanoAppId() == mNanoAppId) 279 && (other.getMessageType() == mMessageType) 280 && (other.isBroadcastMessage() == mIsBroadcasted) 281 && Arrays.equals(other.getMessageBody(), mMessageBody) 282 && (!Flags.reliableMessage() 283 || (other.isReliable() == mIsReliable)) 284 && (!Flags.reliableMessage() 285 || (other.getMessageSequenceNumber() == mMessageSequenceNumber)); 286 } 287 288 return isEqual; 289 } 290 291 @Override hashCode()292 public int hashCode() { 293 if (!Flags.fixApiCheck()) { 294 return super.hashCode(); 295 } 296 297 return Objects.hash(mNanoAppId, mMessageType, mIsBroadcasted, 298 Arrays.hashCode(mMessageBody), mIsReliable, 299 mMessageSequenceNumber); 300 } 301 } 302