1 /* 2 * Copyright 2024 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.nfc; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.time.Instant; 30 31 /** 32 * A log class for OEMs to get log information of NFC events. 33 * @hide 34 */ 35 @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) 36 @SystemApi 37 public final class OemLogItems implements Parcelable { 38 /** 39 * Used when RF field state is changed. 40 */ 41 public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 0X01; 42 /** 43 * Used when NFC is toggled. Event should be set to {@link LogEvent#EVENT_ENABLE} or 44 * {@link LogEvent#EVENT_DISABLE} if this action is used. 45 */ 46 public static final int LOG_ACTION_NFC_TOGGLE = 0x0201; 47 /** 48 * Used when sending host routing status. 49 */ 50 public static final int LOG_ACTION_HCE_DATA = 0x0204; 51 /** 52 * Used when screen state is changed. 53 */ 54 public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 0x0206; 55 /** 56 * Used when tag is detected. 57 */ 58 public static final int LOG_ACTION_TAG_DETECTED = 0x03; 59 60 /** 61 * @hide 62 */ 63 @IntDef(prefix = { "LOG_ACTION_" }, value = { 64 LOG_ACTION_RF_FIELD_STATE_CHANGED, 65 LOG_ACTION_NFC_TOGGLE, 66 LOG_ACTION_HCE_DATA, 67 LOG_ACTION_SCREEN_STATE_CHANGED, 68 LOG_ACTION_TAG_DETECTED, 69 }) 70 @Retention(RetentionPolicy.SOURCE) 71 public @interface LogAction {} 72 73 /** 74 * Represents the event is not set. 75 */ 76 public static final int EVENT_UNSET = 0; 77 /** 78 * Represents nfc enable is called. 79 */ 80 public static final int EVENT_ENABLE = 1; 81 /** 82 * Represents nfc disable is called. 83 */ 84 public static final int EVENT_DISABLE = 2; 85 /** @hide */ 86 @IntDef(prefix = { "EVENT_" }, value = { 87 EVENT_UNSET, 88 EVENT_ENABLE, 89 EVENT_DISABLE, 90 }) 91 @Retention(RetentionPolicy.SOURCE) 92 public @interface LogEvent {} 93 private int mAction; 94 private int mEvent; 95 private int mCallingPid; 96 private byte[] mCommandApdus; 97 private byte[] mResponseApdus; 98 private Instant mRfFieldOnTime; 99 private Tag mTag; 100 101 /** @hide */ OemLogItems(@ogAction int action, @LogEvent int event, int callingPid, byte[] commandApdus, byte[] responseApdus, Instant rfFieldOnTime, Tag tag)102 public OemLogItems(@LogAction int action, @LogEvent int event, int callingPid, 103 byte[] commandApdus, byte[] responseApdus, Instant rfFieldOnTime, 104 Tag tag) { 105 mAction = action; 106 mEvent = event; 107 mTag = tag; 108 mCallingPid = callingPid; 109 mCommandApdus = commandApdus; 110 mResponseApdus = responseApdus; 111 mRfFieldOnTime = rfFieldOnTime; 112 } 113 114 /** 115 * Describe the kinds of special objects contained in this Parcelable 116 * instance's marshaled representation. For example, if the object will 117 * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)}, 118 * the return value of this method must include the 119 * {@link #CONTENTS_FILE_DESCRIPTOR} bit. 120 * 121 * @return a bitmask indicating the set of special object types marshaled 122 * by this Parcelable object instance. 123 */ 124 @Override describeContents()125 public int describeContents() { 126 return 0; 127 } 128 129 /** 130 * Flatten this object in to a Parcel. 131 * 132 * @param dest The Parcel in which the object should be written. 133 * @param flags Additional flags about how the object should be written. 134 * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. 135 */ 136 @Override writeToParcel(@onNull Parcel dest, int flags)137 public void writeToParcel(@NonNull Parcel dest, int flags) { 138 dest.writeInt(mAction); 139 dest.writeInt(mEvent); 140 dest.writeInt(mCallingPid); 141 dest.writeInt(mCommandApdus.length); 142 dest.writeByteArray(mCommandApdus); 143 dest.writeInt(mResponseApdus.length); 144 dest.writeByteArray(mResponseApdus); 145 dest.writeBoolean(mRfFieldOnTime != null); 146 if (mRfFieldOnTime != null) { 147 dest.writeLong(mRfFieldOnTime.getEpochSecond()); 148 dest.writeInt(mRfFieldOnTime.getNano()); 149 } 150 dest.writeParcelable(mTag, 0); 151 } 152 153 /** @hide */ 154 public static class Builder { 155 private final OemLogItems mItem; 156 Builder(@ogAction int type)157 public Builder(@LogAction int type) { 158 mItem = new OemLogItems(type, EVENT_UNSET, 0, new byte[0], new byte[0], null, null); 159 } 160 161 /** Setter of the log action. */ setAction(@ogAction int action)162 public OemLogItems.Builder setAction(@LogAction int action) { 163 mItem.mAction = action; 164 return this; 165 } 166 167 /** Setter of the log calling event. */ setCallingEvent(@ogEvent int event)168 public OemLogItems.Builder setCallingEvent(@LogEvent int event) { 169 mItem.mEvent = event; 170 return this; 171 } 172 173 /** Setter of the log calling Pid. */ setCallingPid(int pid)174 public OemLogItems.Builder setCallingPid(int pid) { 175 mItem.mCallingPid = pid; 176 return this; 177 } 178 179 /** Setter of APDU command. */ setApduCommand(byte[] apdus)180 public OemLogItems.Builder setApduCommand(byte[] apdus) { 181 mItem.mCommandApdus = apdus; 182 return this; 183 } 184 185 /** Setter of RF field on time. */ setRfFieldOnTime(Instant time)186 public OemLogItems.Builder setRfFieldOnTime(Instant time) { 187 mItem.mRfFieldOnTime = time; 188 return this; 189 } 190 191 /** Setter of APDU response. */ setApduResponse(byte[] apdus)192 public OemLogItems.Builder setApduResponse(byte[] apdus) { 193 mItem.mResponseApdus = apdus; 194 return this; 195 } 196 197 /** Setter of dispatched tag. */ setTag(Tag tag)198 public OemLogItems.Builder setTag(Tag tag) { 199 mItem.mTag = tag; 200 return this; 201 } 202 203 /** Builds an {@link OemLogItems} instance. */ build()204 public OemLogItems build() { 205 return mItem; 206 } 207 } 208 209 /** 210 * Gets the action of this log. 211 * @return one of {@link LogAction} 212 */ 213 @LogAction getAction()214 public int getAction() { 215 return mAction; 216 } 217 218 /** 219 * Gets the event of this log. This will be set to {@link LogEvent#EVENT_ENABLE} or 220 * {@link LogEvent#EVENT_DISABLE} only when action is set to 221 * {@link LogAction#LOG_ACTION_NFC_TOGGLE} 222 * @return one of {@link LogEvent} 223 */ 224 @LogEvent getEvent()225 public int getEvent() { 226 return mEvent; 227 } 228 229 /** 230 * Gets the calling Pid of this log. This field will be set only when action is set to 231 * {@link LogAction#LOG_ACTION_NFC_TOGGLE} 232 * @return calling Pid 233 */ getCallingPid()234 public int getCallingPid() { 235 return mCallingPid; 236 } 237 238 /** 239 * Gets the command APDUs of this log. This field will be set only when action is set to 240 * {@link LogAction#LOG_ACTION_HCE_DATA} 241 * @return a byte array of command APDUs with the same format as 242 * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])} 243 */ 244 @Nullable getCommandApdu()245 public byte[] getCommandApdu() { 246 return mCommandApdus; 247 } 248 249 /** 250 * Gets the response APDUs of this log. This field will be set only when action is set to 251 * {@link LogAction#LOG_ACTION_HCE_DATA} 252 * @return a byte array of response APDUs with the same format as 253 * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])} 254 */ 255 @Nullable getResponseApdu()256 public byte[] getResponseApdu() { 257 return mResponseApdus; 258 } 259 260 /** 261 * Gets the RF field event time in this log in millisecond. This field will be set only when 262 * action is set to {@link LogAction#LOG_ACTION_RF_FIELD_STATE_CHANGED} 263 * @return an {@link Instant} of RF field event time. 264 */ 265 @Nullable getRfFieldEventTimeMillis()266 public Instant getRfFieldEventTimeMillis() { 267 return mRfFieldOnTime; 268 } 269 270 /** 271 * Gets the tag of this log. This field will be set only when action is set to 272 * {@link LogAction#LOG_ACTION_TAG_DETECTED} 273 * @return a detected {@link Tag} in {@link #LOG_ACTION_TAG_DETECTED} case. Return 274 * null otherwise. 275 */ 276 @Nullable getTag()277 public Tag getTag() { 278 return mTag; 279 } 280 byteToHex(byte[] bytes)281 private String byteToHex(byte[] bytes) { 282 char[] HexArray = "0123456789ABCDEF".toCharArray(); 283 char[] hexChars = new char[bytes.length * 2]; 284 for (int j = 0; j < bytes.length; j++) { 285 int v = bytes[j] & 0xFF; 286 hexChars[j * 2] = HexArray[v >>> 4]; 287 hexChars[j * 2 + 1] = HexArray[v & 0x0F]; 288 } 289 return new String(hexChars); 290 } 291 292 @Override toString()293 public String toString() { 294 return "[mCommandApdus: " 295 + ((mCommandApdus != null) ? byteToHex(mCommandApdus) : "null") 296 + "[mResponseApdus: " 297 + ((mResponseApdus != null) ? byteToHex(mResponseApdus) : "null") 298 + ", mCallingApi= " + mEvent 299 + ", mAction= " + mAction 300 + ", mCallingPId = " + mCallingPid 301 + ", mRfFieldOnTime= " + mRfFieldOnTime; 302 } OemLogItems(Parcel in)303 private OemLogItems(Parcel in) { 304 this.mAction = in.readInt(); 305 this.mEvent = in.readInt(); 306 this.mCallingPid = in.readInt(); 307 this.mCommandApdus = new byte[in.readInt()]; 308 in.readByteArray(this.mCommandApdus); 309 this.mResponseApdus = new byte[in.readInt()]; 310 in.readByteArray(this.mResponseApdus); 311 boolean isRfFieldOnTimeSet = in.readBoolean(); 312 if (isRfFieldOnTimeSet) { 313 this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt()); 314 } else { 315 this.mRfFieldOnTime = null; 316 } 317 this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class); 318 } 319 320 public static final @NonNull Parcelable.Creator<OemLogItems> CREATOR = 321 new Parcelable.Creator<OemLogItems>() { 322 @Override 323 public OemLogItems createFromParcel(Parcel in) { 324 return new OemLogItems(in); 325 } 326 327 @Override 328 public OemLogItems[] newArray(int size) { 329 return new OemLogItems[size]; 330 } 331 }; 332 333 } 334