I use the processCommandApdu() method in a subclass of HostApduService to react on NFC commands. This method gets called on the Android main thread. These commands should be processed and sent over the NFC channel sequentially. Therefore, I want to process them synchronously.
Is there any good way to enforce sequential order without blocking inside of the processCommandApdu() method?
There is no need for you to synchronize command processing. Sequencing is inherent to the ISO/IEC 14443 protocol: A command exchange always consists of a command sent by the reader to the card (HCE device) and a response sent by the card (HCE) device to the reader. A reader won't issue a new command before the response to the previous command was received. If a command times out before a response is received by the reader, the reader will interpret this as if the connection to the card was lost.
Therefore, unless the reader resets/drops the connection, you won't receive a new command before you sent a response to the previous command (either through returning no-null from processCommandApdu()) or by calling sendResponseApdu()).
Related
In my Android app I have an implementation of HostApduService. Here is a snippet of it's implementation:
public final class MyHostApduService extends HostApduService {
private boolean disconnected = false;
#Override
public byte[] processCommandApdu(byte[] commandApdu, #Nullable Bundle extras) {
//process apdu in a background thread and call sendResponseApdu() when ready
Single.fromCallable(() -> processInternal(commandApdu))
.subscribeOn(nfcScheduler)
.subscribe(this::sendResponseApdu, t -> Log.e("could not create response", t));
return null;
}
...
#Override
public void onDeactivated(int reason) {
disconnected = true;
}
private void processInternal(byte[] apdu) {
//business logic
if(!disconnected) {
//last message was probably received by the terminal
}
}
}
So in my observation the onDeactivated() callback can come right in the middle of a processCommandApdu() and even then the OS seems to recognize a bit earlier that the NFC field is lost than onDeactivated() is called.
Here is an example of a lost field during the communication:
16:21:16.808 I/MyHostApduService : processApdu[request|13bytes] 0A4040007A000000004306000
16:21:16.811 D/MyHostApduService : do business logic
16:21:16.890 D/HostEmulationManager: notifyHostEmulationDeactivated
16:21:16.890 D/HostEmulationManager: Unbinding from service ComponentInfo{app.debug/internal.MyHostApduService}
16:21:16.890 I/MyHostApduService : onDeactivated LINK_LOSS
16:21:16.898 I/MyHostApduService : processApdu[response|2bytes|90ms] 6A82
The problem is that I need to confidently check if the last message was received or dropped, because some important finalization code has to be executed (but only if the terminal receives the message). Is there a better way to check if a message was received than to use onDeactivated() (which seems to be quite non-deterministic in its timing)?
You can't. Instead you will need to adapt your communication protocol if you really need to reliably detect that case.
The problem is not really Android but the underlying communication protocols (ISO/IEC 7816-4 over ISO/IEC 14443-4). These protocols were built for communication with regular smartcards. Smartcards being fully passive devices which can't continue processing (due to lack of energy) when pulled out of a reader or away from the NFC RF field.
The protocol stack is designed for interrogator driven communication (where the interrogator is the terminal). Communication is performed in command-response sequences. In principal, each command-response sequence consists of the following steps (with a few additional corner cases):
Terminal sends a command.
Smartcard receives and processes the command.
Smartcard sends response data and concludes with a status word.
Neither the application protocol (ISO/IEC 7816-4) nor the transmission protocol (ISO/IEC 14443-4 aka ISO-DEP) confirm the smartcard response by any form of acknowledgement. Once the smartcard sent its response it is deemed to have finished processing.
In effect this would not be an issue for a classic smartcard (contact or contactless). An interrupted communication would cause the card to be power-cycled (either because the link-loss also implies a power-loss or because the terminal performs an explicit reset). So the smartcard would not be able to rely on cleanup sequences at that point.
However, that does not mean that there are no ways to overcome that limitation. Classic smartcards maintain persistent state even across power-cycles. Critical operations are performed as atomic transactions. In case of power-loss, cleanup/rollback is typically performed upon reset (boot-up). However, that's not quite easy to map to Android since link-loss does not cause execution on the HCE side to be interrupted. Consequently, there's no way to detect that the HCE smartcard was pulled before a response was sent back to the reader. Nevertheless, there's also no atomic transactions that would be interrupted by the link-loss. Hence, reset (i.e. the reception of the SELECT (by DF name) command that selects your application) is still the right place to perform cleanup such as resetting application state.
With regard to your specific requirement, a typical approach would be to adapt the application-level protocol and add an acknowledgment command that confirms reception of the (then second-)last response. I.e. if you currently have something like:
T---> SELECT APPLICATION
<---C FCI | 9000
T---> PERFORM CRITICAL OPERATION
<---C CRITICAL OPERATION RESULT
You could adapt the protocol to include a final acknowledgement:
T---> SELECT APPLICATION
<---C FCI | 9000
T---> PERFORM CRITICAL OPERATION
<---C CRITICAL OPERATION RESULT
T---> CONFIRM RECEPTION OF RESULT
<---C 9000
Now you would not really care if the final response (9000) is lost on its way to the terminal.
In, short: it is not possible to check if a message was received by the terminal as the role of a card (in HCE). The T=CL (ISO7816) protocol does not provide an ack when chunking the data during NFC communication for the last chunk.
Furthermore, using NFC in Android is communicating with the com.android.nfc.NfcService through a Messenger. This is exactly what e.g. HostApduService or HostNfcFService does.
There are 3 basic signals:
MSG_COMMAND_APDU = 0
MSG_RESPONSE_APDU = 1
MSG_DEACTIVATED = 2
The application service first receives a signal 0 (MSG_COMMAND_APDU) and response with a 1 (MSG_RESPONSE_APDU) type signal. At any point in time a 2 (MSG_DEACTIVATED) can happen. Now the application can check if after a command request, a deactivate was received BEFORE the response was send. This works well most of the time, but it is not consistent. It is not uncommon that the deactivate signal is received 100+ms after the actual deactivating therefore it seems that the response was sent. And even with this check you can only know when you passed the message to the NfcService, the actual transmission also takes some time (about couple of µs per byte).
So in the end, you can only tell if a response was definitely NOT received by the terminal (when the deactivate is before the response) but otherwise you are at the mercy of the NfcService and it's HAL implementation or the driver.
I'm experimenting problems between my NFC reader and my NFC Smarthphone (I am using Host-based Card Emulation). The problem is the following...
My android application is able to receive the APDU to select the AID and I am able to return a result for the reader.
After that, I try to send a specific command to reader and get the response. I receive the call in my override method processCommandApdu and when It return the result, I receive an event in onDeactivated method which reason is DEACTIVATION_LINK_LOSS (my phone is very close of the reader).
Have you any idea about it?
Background: Commands are always initiated by the terminal. Your processCommandApdu() method is there to take that command the terminal sends, and then send back a response in the format that the terminal requires. It depends on what type of application you are creating and what kind of terminal you are using for development.
Answer: [DEACTIVATION_LINK_LOSS] happens when the terminal is done sending commands out and the NFC connection between the device and the terminal is terminated. This has nothing to do with the fact that your phone is close or not, this only has to do with the fact that the terminal is done with it's communication and the connection between the device is no longer there.
Documentation:
https://developer.android.com/reference/android/nfc/cardemulation/HostApduService.html#DEACTIVATION_LINK_LOSS
Using a Nexus 4 and the latest Android API level 18 to communicate with a Mifare DESFire EV1 AES tag is giving me a headache. Following the NXP native protocol in order to write and read this type of tag, these steps must be followed:
Select application
Authenticate
Write or Read
To do it so, I use Android's IsoDep class which provides access to ISO 14443-4 properties and I/O operations. The very weird thing about it is that once I send the select application native command I get an unexpected response. Imagine I have the AID F4013D so I send:
-> 5AF4013D
<- 6E00
All possible responses must be one byte length (success 0x00 or error_code) and never two or more. Thus, the 0x6E before the success response is absolutely unexpected. It does not happen always, and when it does not and works fine, the select application and authentication processes work fine. However once authenticated the write command does not have a correct behavior, all write commands finishes with a 0xAF from the PICC instead of a success 0x00. It seems like the PICC expect some extra data when it should not (I send the correct length payload). If I send any other command I get a 0xCA (Command Aborted) error code.
-> 5AF4013D
<- 00 /*Success*/
-> AA01
<- AFA8394ED57A5E83106B4EE72FD2BB0CC4
-> AF148F525E1DDE0AD6AB60B4B615552475C91F2E8D89B8523E4465113DD5BD19C6
<- 0066D255C93F2F492AFE3715C88964F1BD /*Authentication success*/
-> 3D02000000030000222222 /*Write 3 bytes to file nº2*/
<- AF /*Unexpected, 0x00 was expected*/
As it is normal, if I send these type of commands with a personal reader (non Android NFC) it always works fine. It seems that something in the Android NFC API is going strange, when it should just be a raw data transporter which never interprets or modifies data.
I have also tried with ISO 7816-4 APDU structure with the same result. As a curiosity, with a Galaxy Nexus does not happen the select application strange response, but yes the write command one always.
(1) For the first part concerning the status code 6E00:
6E 00 is not a "strange byte 0x6E + success status code 0x00". Instead it is a response APDU status word 6E 00 ("Class not supported"). This indicates that there was previous communication with the card using APDU-based access (e.g. Android itself tried to read the card as Type 4 tag and did not reset the connection afterwards). Thus, the card will expect all further communication to be in ISO 7816-4 APDUs. In that case (i.e. if you receive an ISO 7816-4 status code like 6E 00), you could continue using DESFire APDU wrapped commands by simply wrapping your native commands.
EDIT: In fact, this is somewhat expected behavior on an NFC device. The idea is that an NFC device will automatically scan detected tags for NDEF messages. In the case of a DESFire card, the NFC device will detect the card as potential Type 4 tag. Thus the NFC device will send ISO 7816-4 APDUs as it would send to any other Type 4 tag. Hence, if the NFC device doesn't reset the communication with the tag before handing the detected tag to the app, the app can only communicate using ISO 7816-4 APDUs. Note, however, that I would consider it a bug that this happens only for some activations on the same device. In my opinion, the behavior on one specific device model should be consistent.
EDIT: While I would not consider this behavior a bug, it is actually caused by a known bug (#58773) in Android's NFC stack for devices with Broadcom NFC controller. On affected devices, the automatic presence check sends ISO 7816-4 APDUs at timed intervals that cause DESFire cards to switch into ISO 7816-4 APDU mode.
(2) For the second part concerning the (unexpected) response code 0xAF:
Could it be that your file's communication settings are setup for either "plain communication secured by MACing" or "fully enciphered communication"? In that case, simply sending the three data bytes would not be enough. Instead you would need to send either the plain data plus MAC or the padded, CRCed and encyrypted data. Hence the 0xAF indicating that the card expects further data.
EDIT: So to summarize the comments below. After sending further bytes (one byte at a time for each received 0xAF status code: AF FF) it turned out that exactly 8 more bytes were expected by the card. 8 bytes is exactly the size of the CMAC for AES authentication. Thus, the communication settings were set to "plain communication secured by MACing".
I'm developing an Android App which i want to communicate with a device connected via USB. This device is delivering data all the time. These data are visible with a programm on the android linux shell.
My goal is to see those data in my App and after that deliver them via a Service to other Apps.
So my question is: Can i "open" a connection from my Android App to the USB-Port so im continuesly receiveing the data in my app, which are sent by the usb-device? And if yes, how would the code look like?
*Edit
Thank you for your answers, the app itself doesn't run on the commandline any more. So its no executable anymore but a shared library getting load by my android app.
It did before, but i want to be able to initiate the connection using NDK methods in my App to be able to see the data in my App itself. So I've tried to see if a connection is allready open.
I've added some functions to my code, so i can see if the usb-connection is open and i have the permission to that usb device.
UsbManager.hasPermission(device)
returns true, because I'm using an itent filter.
UsbManager.openDevice(device)
returns an UsbDeviceConnection, so i seem to have the access to use that device.
What im not capable of so far is receiving either iniciating the bus connection to by usb-device and of course either getting data input of that device.
Since my native code allready has a while(true)-method which is only using callbacks to send data to my app when actually data getting sent trough my usb-device i want to keep the work done in my c-code.
The only job my app should do is open the bus-connection once and after that be ready for callback from the c-code.
Is that possible?
If you have the app that runs on the command line, you can actually run a command line from within your app. Take a look at the Process class and the ProcessBuilder docs for full details. The example given is below
To run /system/bin/ping to ping android.com:
Process process = new ProcessBuilder()
.command("/system/bin/ping", "android.com")
.redirectErrorStream(true)
.start();
try {
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
readStream(in);
finally {
process.destroy();
}
}
I would like to know high level idea of how Android Modem code will call/pass message to Android application layer. Say we take SMS for example. If network sends SMS and Modem (say Qualcomm C code parses it) how is it transmitted to Android Application layer?
Is there always a JNI call happening? as interface between modem and Android? Can you please share the information with us. Thanks
In almost all android source base as found in the AOSP/CAF/CM source (Android Open Source Project, CodeAurora Forum, Cyanogenmod respectively), will have C code called the rild, (Radio Interface Layer Daemon). This is commonly found within the /hardware/ril of the source tree.
This daemon runs from the moment Android boots up, and creates a socket called /dev/socket/rild and /dev/socket/rild-debug. There will be a proprietary library coming from Qualcomm, HTC, that gets dynamically loaded at run time upon boot. It is that proprietary library that in turn, communicates to the radio firmware. And the rild's hooks for the call-backs into the proprietary library is established there and then.
At the rild layer, via the aforementioned socket, is how the Android layer (found in the source tree, frameworks/base/telephony/com/android/internal/telephony/RIL.java) communicates.
On the Java side, it opens the socket for reading/writing, along with establishing intents and setting up delegates for broadcasting/receiving events via this socket.
For example, an incoming call, the proprietary library, invokes a callback hook as set up by rild. The rild writes standard generic AT Hayes modem commands to the socket, on the Java side, it reads and interprets the modem commands, and from there, the PhoneManager broadcasts CALL_STATE_RINGING, in which Phone application (found in the source packages/apps/Phone) has registered a receiver and kickstarts the User interface, and that is how you get to answer the call.
Another example, making an outgoing call, you dial a number on Android, the intent gets created and which in turn the PhoneManager (This is the root of it all, here, cannot remember top of my head, think its in frameworks/base/core/java somewhere in the source tree) receives the intent, convert it into either a sequence of AT Hayes modem commands, write it out to the socket, the rild then invokes a callback to the proprietary library, the proprietary library in turn delegates to the radio firmware.
Final example, sending text messages, from the Messaging (found in packages/apps/Mms source tree) application, the text you type, gets shoved into an intent, the PhoneManager receives the intent, converts the text into GSM-encoded using 7-bit GSM letters (IIRC), gets written out to the socket, the rild in turn invokes a callback to the proprietary library, the proprietary library in turn delegates to the radio firmware and the text has now left the domain of the handset and is in the airwaves somewhere... :) Along with sending a broadcast message within Android itself, provided that READ_PHONE_STATE permission is used and specified in the AndroidManifest.xml.
Likewise conversely, when receiving a text message, it is in the reverse, radio firmware receives some bytes, the proprietary library invokes the callback to the rild, and thus writes out the bytes to the socket. On the Java side, it reads from it, and decodes the sequence of bytes, converts it to text as we know of, fires a broadcast with a message received notification. The Messaging application in turn, has registered receivers for the said broadcast, and sends an intent to the notification bar to say something like "New message received from +xxxxxx"
The intents are found in frameworks/base/telephony/java/com/android/internal/telephony/TelephonyIntents.java
That is the gist of how the telephony system works, the real beauty is, that it uses generic AT Hayes modem commands thusly simplifying and hiding the real proprietary mechanisms.
As for the likes of Qualcomm, HTC, forget about it in thinking they'd ever open source the library in question because the radio telephony layer is embedded within the S-o-C (System on a Chip) circuitry!
Which is also, as a side note, why its risky to flash radio firmware, some handsets provide the capability to do it, flash the wrong firmware (such as an incompatible or not suitable for handset), kiss the handset good-bye and use that as a door stopper or paper-weight! :)
It should be noted, that there is zero JNI mechanisms involved.
This is from my understanding of how it works, from what I can tell is this, the radio firmware is loaded into a memory address somewhere where the linux kernel has reserved the address space and does not touch it, something like back in the old PC days when DOS booted up, there was reserved addresses used by the BIOS, I think, its similar here, the addresses marked as reserved are occupied by the firmware, in which the proprietary radio library talks to it - and since the library is running in the address space owned by the kernel, a lá owned by root with root privileges, it can "talk" to it, if you think of using the old BASIC dialect of peek and poke, I'd guess you would not be far off the mark there, by writing a certain sequence of bytes to that address, the radio firmware acts on it, almost like having a interrupt vector table... this am guessing here how it works exactly. :)
Continuing from the explanation by t0mm13b, When we talk about a smartphone, think of 3 layer operations wrt to SMS/Calls.
RIL (User level) <-> AP <-> CP
AP : Application Processor(Where your Android OS runs. Think of games, songs, videos, camera etc running on this processor)
CP : Cellular Processor (Which actually deals with Air-interface for incoming/outgoing calls/sms, interacts with Network Tower etc ..)
Now let say some data is received at CP side (It could be internet data/sms/call). Now there are certain logical channels between AP and CP. So CP will push the data received to a corresponding channel based on type of data. This data will be received by AP. AP will send this data back to RIL/App. RIL will decode this data (specially call/sms data). Based on that gives notification to User about SMS/Call.