• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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