blob: 5867b3ca4af6d118fc80da807c0e6c788139b35b [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.nfc.cardemulation;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.nfc.cardemulation.NfcFServiceInfo;
import android.nfc.cardemulation.NfcFCardEmulation;
import android.nfc.cardemulation.HostNfcFService;
import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import com.google.android.collect.Maps;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
public class RegisteredNfcFServicesCache {
static final String XML_INDENT_OUTPUT_FEATURE = "http://xmlpull.org/v1/doc/features.html#indent-output";
static final String TAG = "RegisteredNfcFServicesCache";
static final boolean DBG = false;
final Context mContext;
final AtomicReference<BroadcastReceiver> mReceiver;
final Object mLock = new Object();
// All variables below synchronized on mLock
// mUserServices holds the card emulation services that are running for each user
final SparseArray<UserServices> mUserServices = new SparseArray<UserServices>();
final Callback mCallback;
final AtomicFile mDynamicSystemCodeNfcid2File;
boolean mActivated = false;
boolean mUserSwitched = false;
public interface Callback {
void onNfcFServicesUpdated(int userId, final List<NfcFServiceInfo> services);
};
static class DynamicSystemCode {
public final int uid;
public final String systemCode;
DynamicSystemCode(int uid, String systemCode) {
this.uid = uid;
this.systemCode = systemCode;
}
};
static class DynamicNfcid2 {
public final int uid;
public final String nfcid2;
DynamicNfcid2(int uid, String nfcid2) {
this.uid = uid;
this.nfcid2 = nfcid2;
}
};
private static class UserServices {
/**
* All services that have registered
*/
final HashMap<ComponentName, NfcFServiceInfo> services =
Maps.newHashMap(); // Re-built at run-time
final HashMap<ComponentName, DynamicSystemCode> dynamicSystemCode =
Maps.newHashMap(); // In memory cache of dynamic System Code store
final HashMap<ComponentName, DynamicNfcid2> dynamicNfcid2 =
Maps.newHashMap(); // In memory cache of dynamic NFCID2 store
};
private UserServices findOrCreateUserLocked(int userId) {
UserServices userServices = mUserServices.get(userId);
if (userServices == null) {
userServices = new UserServices();
mUserServices.put(userId, userServices);
}
return userServices;
}
public RegisteredNfcFServicesCache(Context context, Callback callback) {
mContext = context;
mCallback = callback;
final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
String action = intent.getAction();
if (DBG) Log.d(TAG, "Intent action: " + action);
if (uid != -1) {
boolean replaced = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) &&
(Intent.ACTION_PACKAGE_ADDED.equals(action) ||
Intent.ACTION_PACKAGE_REMOVED.equals(action));
if (!replaced) {
int currentUser = ActivityManager.getCurrentUser();
if (currentUser == UserHandle.getUserId(uid)) {
invalidateCache(UserHandle.getUserId(uid));
} else {
// Cache will automatically be updated on user switch
}
} else {
if (DBG) Log.d(TAG,
"Ignoring package intent due to package being replaced.");
}
}
}
};
mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_FIRST_LAUNCH);
intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
intentFilter.addDataScheme("package");
mContext.registerReceiverAsUser(mReceiver.get(), UserHandle.ALL, intentFilter, null, null);
// Register for events related to sdcard operations
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiverAsUser(mReceiver.get(), UserHandle.ALL, sdFilter, null, null);
File dataDir = mContext.getFilesDir();
mDynamicSystemCodeNfcid2File =
new AtomicFile(new File(dataDir, "dynamic_systemcode_nfcid2.xml"));
}
void initialize() {
synchronized (mLock) {
readDynamicSystemCodeNfcid2Locked();
}
invalidateCache(ActivityManager.getCurrentUser());
}
void dump(ArrayList<NfcFServiceInfo> services) {
for (NfcFServiceInfo service : services) {
Log.d(TAG, service.toString());
}
}
boolean containsServiceLocked(ArrayList<NfcFServiceInfo> services,
ComponentName componentName) {
for (NfcFServiceInfo service : services) {
if (service.getComponent().equals(componentName)) return true;
}
return false;
}
public boolean hasService(int userId, ComponentName componentName) {
return getService(userId, componentName) != null;
}
public NfcFServiceInfo getService(int userId, ComponentName componentName) {
synchronized (mLock) {
UserServices userServices = findOrCreateUserLocked(userId);
return userServices.services.get(componentName);
}
}
public List<NfcFServiceInfo> getServices(int userId) {
final ArrayList<NfcFServiceInfo> services = new ArrayList<NfcFServiceInfo>();
synchronized (mLock) {
UserServices userServices = findOrCreateUserLocked(userId);
services.addAll(userServices.services.values());
}
return services;
}
ArrayList<NfcFServiceInfo> getInstalledServices(int userId) {
if (DBG) Log.d(TAG, "getInstalledServices");
PackageManager pm;
try {
pm = mContext.createPackageContextAsUser("android", 0,
new UserHandle(userId)).getPackageManager();
} catch (NameNotFoundException e) {
Log.e(TAG, "Could not create user package context");
return null;
}
ArrayList<NfcFServiceInfo> validServices = new ArrayList<NfcFServiceInfo>();
List<ResolveInfo> resolvedServices = pm.queryIntentServicesAsUser(
new Intent(HostNfcFService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA, userId);
for (ResolveInfo resolvedService : resolvedServices) {
try {
ServiceInfo si = resolvedService.serviceInfo;
ComponentName componentName = new ComponentName(si.packageName, si.name);
// Check if the package holds the NFC permission
if (pm.checkPermission(android.Manifest.permission.NFC, si.packageName) !=
PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "Skipping NfcF service " + componentName +
": it does not require the permission " +
android.Manifest.permission.NFC);
continue;
}
if (!android.Manifest.permission.BIND_NFC_SERVICE.equals(
si.permission)) {
Log.e(TAG, "Skipping NfcF service " + componentName +
": it does not require the permission " +
android.Manifest.permission.BIND_NFC_SERVICE);
continue;
}
NfcFServiceInfo service = new NfcFServiceInfo(pm, resolvedService);
if (service != null) {
validServices.add(service);
}
} catch (XmlPullParserException e) {
Log.w(TAG, "Unable to load component info " + resolvedService.toString(), e);
} catch (IOException e) {
Log.w(TAG, "Unable to load component info " + resolvedService.toString(), e);
}
}
return validServices;
}
public void invalidateCache(int userId) {
if (DBG) Log.d(TAG, "invalidateCache");
final ArrayList<NfcFServiceInfo> validServices = getInstalledServices(userId);
if (validServices == null) {
return;
}
ArrayList<NfcFServiceInfo> newServices = null;
synchronized (mLock) {
UserServices userServices = findOrCreateUserLocked(userId);
// Check update
ArrayList<NfcFServiceInfo> cachedServices =
new ArrayList<NfcFServiceInfo>(userServices.services.values());
ArrayList<NfcFServiceInfo> toBeAdded = new ArrayList<NfcFServiceInfo>();
ArrayList<NfcFServiceInfo> toBeRemoved = new ArrayList<NfcFServiceInfo>();
boolean matched = false;
for (NfcFServiceInfo validService : validServices) {
for (NfcFServiceInfo cachedService : cachedServices) {
if (validService.equals(cachedService)) {
matched = true;
break;
}
}
if (!matched) {
toBeAdded.add(validService);
}
matched = false;
}
for (NfcFServiceInfo cachedService : cachedServices) {
for (NfcFServiceInfo validService : validServices) {
if (cachedService.equals(validService)) {
matched = true;
break;
}
}
if (!matched) {
toBeRemoved.add(cachedService);
}
matched = false;
}
if (mUserSwitched) {
Log.d(TAG, "User switched, rebuild internal cache");
mUserSwitched = false;
} else if (toBeAdded.size() == 0 && toBeRemoved.size() == 0) {
Log.d(TAG, "Service unchanged, not updating");
return;
}
// Update cache
for (NfcFServiceInfo service : toBeAdded) {
userServices.services.put(service.getComponent(), service);
if (DBG) Log.d(TAG, "Added service: " + service.getComponent());
}
for (NfcFServiceInfo service : toBeRemoved) {
userServices.services.remove(service.getComponent());
if (DBG) Log.d(TAG, "Removed service: " + service.getComponent());
}
// Apply dynamic System Code mappings
ArrayList<ComponentName> toBeRemovedDynamicSystemCode =
new ArrayList<ComponentName>();
for (Map.Entry<ComponentName, DynamicSystemCode> entry :
userServices.dynamicSystemCode.entrySet()) {
// Verify component / uid match
ComponentName componentName = entry.getKey();
DynamicSystemCode dynamicSystemCode = entry.getValue();
NfcFServiceInfo service = userServices.services.get(componentName);
if (service == null || (service.getUid() != dynamicSystemCode.uid)) {
toBeRemovedDynamicSystemCode.add(componentName);
continue;
} else {
service.setOrReplaceDynamicSystemCode(dynamicSystemCode.systemCode);
}
}
// Apply dynamic NFCID2 mappings
ArrayList<ComponentName> toBeRemovedDynamicNfcid2 =
new ArrayList<ComponentName>();
for (Map.Entry<ComponentName, DynamicNfcid2> entry :
userServices.dynamicNfcid2.entrySet()) {
// Verify component / uid match
ComponentName componentName = entry.getKey();
DynamicNfcid2 dynamicNfcid2 = entry.getValue();
NfcFServiceInfo service = userServices.services.get(componentName);
if (service == null || (service.getUid() != dynamicNfcid2.uid)) {
toBeRemovedDynamicNfcid2.add(componentName);
continue;
} else {
service.setOrReplaceDynamicNfcid2(dynamicNfcid2.nfcid2);
}
}
for (ComponentName removedComponent : toBeRemovedDynamicSystemCode) {
Log.d(TAG, "Removing dynamic System Code registered by " +
removedComponent);
userServices.dynamicSystemCode.remove(removedComponent);
}
for (ComponentName removedComponent : toBeRemovedDynamicNfcid2) {
Log.d(TAG, "Removing dynamic NFCID2 registered by " +
removedComponent);
userServices.dynamicNfcid2.remove(removedComponent);
}
// Assign a NFCID2 for services requesting a random NFCID2, then apply
boolean nfcid2Assigned = false;
for (Map.Entry<ComponentName, NfcFServiceInfo> entry :
userServices.services.entrySet()) {
NfcFServiceInfo service = entry.getValue();
if (service.getNfcid2().equalsIgnoreCase("RANDOM")) {
String randomNfcid2 = generateRandomNfcid2();
service.setOrReplaceDynamicNfcid2(randomNfcid2);
DynamicNfcid2 dynamicNfcid2 =
new DynamicNfcid2(service.getUid(), randomNfcid2);
userServices.dynamicNfcid2.put(entry.getKey(), dynamicNfcid2);
nfcid2Assigned = true;
}
}
// Persist to filesystem
if (toBeRemovedDynamicSystemCode.size() > 0 ||
toBeRemovedDynamicNfcid2.size() > 0 ||
nfcid2Assigned) {
writeDynamicSystemCodeNfcid2Locked();
}
newServices = new ArrayList<NfcFServiceInfo>(userServices.services.values());
}
mCallback.onNfcFServicesUpdated(userId, Collections.unmodifiableList(newServices));
if (DBG) dump(newServices);
}
private void readDynamicSystemCodeNfcid2Locked() {
if (DBG) Log.d(TAG, "readDynamicSystemCodeNfcid2Locked");
FileInputStream fis = null;
try {
if (!mDynamicSystemCodeNfcid2File.getBaseFile().exists()) {
Log.d(TAG, "Dynamic System Code, NFCID2 file does not exist.");
return;
}
fis = mDynamicSystemCodeNfcid2File.openRead();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, null);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.START_TAG &&
eventType != XmlPullParser.END_DOCUMENT) {
eventType = parser.next();
}
String tagName = parser.getName();
if ("services".equals(tagName)) {
ComponentName componentName = null;
int currentUid = -1;
String systemCode = null;
String nfcid2 = null;
String description = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
tagName = parser.getName();
if (eventType == XmlPullParser.START_TAG) {
if ("service".equals(tagName) && parser.getDepth() == 2) {
String compString =
parser.getAttributeValue(null, "component");
String uidString =
parser.getAttributeValue(null, "uid");
String systemCodeString =
parser.getAttributeValue(null, "system-code");
String descriptionString =
parser.getAttributeValue(null, "description");
String nfcid2String =
parser.getAttributeValue(null, "nfcid2");
if (compString == null || uidString == null) {
Log.e(TAG, "Invalid service attributes");
} else {
try {
componentName = ComponentName.unflattenFromString(compString);
currentUid = Integer.parseInt(uidString);
systemCode = systemCodeString;
description = descriptionString;
nfcid2 = nfcid2String;
} catch (NumberFormatException e) {
Log.e(TAG, "Could not parse service uid");
}
}
}
} else if (eventType == XmlPullParser.END_TAG) {
if ("service".equals(tagName)) {
// See if we have a valid service
if (componentName != null && currentUid >= 0) {
final int userId = UserHandle.getUserId(currentUid);
UserServices userServices = findOrCreateUserLocked(userId);
if (systemCode != null) {
DynamicSystemCode dynamicSystemCode =
new DynamicSystemCode(currentUid, systemCode);
userServices.dynamicSystemCode.put(
componentName, dynamicSystemCode);
}
if (nfcid2 != null) {
DynamicNfcid2 dynamicNfcid2 =
new DynamicNfcid2(currentUid, nfcid2);
userServices.dynamicNfcid2.put(
componentName, dynamicNfcid2);
}
}
componentName = null;
currentUid = -1;
systemCode = null;
description = null;
nfcid2 = null;
}
}
eventType = parser.next();
};
}
} catch (Exception e) {
Log.e(TAG, "Could not parse dynamic System Code, NFCID2 file, trashing.");
mDynamicSystemCodeNfcid2File.delete();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
}
}
}
}
private boolean writeDynamicSystemCodeNfcid2Locked() {
if (DBG) Log.d(TAG, "writeDynamicSystemCodeNfcid2Locked");
FileOutputStream fos = null;
try {
fos = mDynamicSystemCodeNfcid2File.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, "utf-8");
out.startDocument(null, true);
out.setFeature(XML_INDENT_OUTPUT_FEATURE, true);
out.startTag(null, "services");
for (int i = 0; i < mUserServices.size(); i++) {
final UserServices userServices = mUserServices.valueAt(i);
for (Map.Entry<ComponentName, DynamicSystemCode> entry :
userServices.dynamicSystemCode.entrySet()) {
out.startTag(null, "service");
out.attribute(null, "component", entry.getKey().flattenToString());
out.attribute(null, "uid", Integer.toString(entry.getValue().uid));
out.attribute(null, "system-code", entry.getValue().systemCode);
if (userServices.dynamicNfcid2.containsKey(entry.getKey())) {
out.attribute(null, "nfcid2",
userServices.dynamicNfcid2.get(entry.getKey()).nfcid2);
}
out.endTag(null, "service");
}
for (Map.Entry<ComponentName, DynamicNfcid2> entry :
userServices.dynamicNfcid2.entrySet()) {
if (!userServices.dynamicSystemCode.containsKey(entry.getKey())) {
out.startTag(null, "service");
out.attribute(null, "component", entry.getKey().flattenToString());
out.attribute(null, "uid", Integer.toString(entry.getValue().uid));
out.attribute(null, "nfcid2", entry.getValue().nfcid2);
out.endTag(null, "service");
}
}
}
out.endTag(null, "services");
out.endDocument();
mDynamicSystemCodeNfcid2File.finishWrite(fos);
return true;
} catch (Exception e) {
Log.e(TAG, "Error writing dynamic System Code, NFCID2", e);
if (fos != null) {
mDynamicSystemCodeNfcid2File.failWrite(fos);
}
return false;
}
}
public boolean registerSystemCodeForService(int userId, int uid,
ComponentName componentName, String systemCode) {
if (DBG) Log.d(TAG, "registerSystemCodeForService");
ArrayList<NfcFServiceInfo> newServices = null;
boolean success;
synchronized (mLock) {
if (mActivated) {
Log.d(TAG, "failed to register System Code during activation");
return false;
}
UserServices userServices = findOrCreateUserLocked(userId);
// Check if we can find this service
NfcFServiceInfo service = getService(userId, componentName);
if (service == null) {
Log.e(TAG, "Service " + componentName + " does not exist.");
return false;
}
if (service.getUid() != uid) {
// This is probably a good indication something is wrong here.
// Either newer service installed with different uid (but then
// we should have known about it), or somebody calling us from
// a different uid.
Log.e(TAG, "UID mismatch.");
return false;
}
if (!systemCode.equalsIgnoreCase("NULL") &&
!NfcFCardEmulation.isValidSystemCode(systemCode)) {
Log.e(TAG, "System Code " + systemCode + " is not a valid System Code");
return false;
}
// Apply dynamic System Code mappings
systemCode = systemCode.toUpperCase();
DynamicSystemCode oldDynamicSystemCode =
userServices.dynamicSystemCode.get(componentName);
DynamicSystemCode dynamicSystemCode = new DynamicSystemCode(uid, systemCode);
userServices.dynamicSystemCode.put(componentName, dynamicSystemCode);
success = writeDynamicSystemCodeNfcid2Locked();
if (success) {
service.setOrReplaceDynamicSystemCode(systemCode);
newServices = new ArrayList<NfcFServiceInfo>(userServices.services.values());
} else {
Log.e(TAG, "Failed to persist System Code.");
// Undo registration
if (oldDynamicSystemCode == null) {
userServices.dynamicSystemCode.remove(componentName);
} else {
userServices.dynamicSystemCode.put(componentName, oldDynamicSystemCode);
}
}
}
if (success) {
// Make callback without the lock held
mCallback.onNfcFServicesUpdated(userId, newServices);
}
return success;
}
public String getSystemCodeForService(int userId, int uid, ComponentName componentName) {
if (DBG) Log.d(TAG, "getSystemCodeForService");
NfcFServiceInfo service = getService(userId, componentName);
if (service != null) {
if (service.getUid() != uid) {
Log.e(TAG, "UID mismatch");
return null;
}
return service.getSystemCode();
} else {
Log.e(TAG, "Could not find service " + componentName);
return null;
}
}
public boolean removeSystemCodeForService(int userId, int uid, ComponentName componentName) {
if (DBG) Log.d(TAG, "removeSystemCodeForService");
return registerSystemCodeForService(userId, uid, componentName, "NULL");
}
public boolean setNfcid2ForService(int userId, int uid,
ComponentName componentName, String nfcid2) {
if (DBG) Log.d(TAG, "setNfcid2ForService");
ArrayList<NfcFServiceInfo> newServices = null;
boolean success;
synchronized (mLock) {
if (mActivated) {
Log.d(TAG, "failed to set NFCID2 during activation");
return false;
}
UserServices userServices = findOrCreateUserLocked(userId);
// Check if we can find this service
NfcFServiceInfo service = getService(userId, componentName);
if (service == null) {
Log.e(TAG, "Service " + componentName + " does not exist.");
return false;
}
if (service.getUid() != uid) {
// This is probably a good indication something is wrong here.
// Either newer service installed with different uid (but then
// we should have known about it), or somebody calling us from
// a different uid.
Log.e(TAG, "UID mismatch.");
return false;
}
if (!NfcFCardEmulation.isValidNfcid2(nfcid2)) {
Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2");
return false;
}
// Apply dynamic NFCID2 mappings
nfcid2 = nfcid2.toUpperCase();
DynamicNfcid2 oldDynamicNfcid2 = userServices.dynamicNfcid2.get(componentName);
DynamicNfcid2 dynamicNfcid2 = new DynamicNfcid2(uid, nfcid2);
userServices.dynamicNfcid2.put(componentName, dynamicNfcid2);
success = writeDynamicSystemCodeNfcid2Locked();
if (success) {
service.setOrReplaceDynamicNfcid2(nfcid2);
newServices = new ArrayList<NfcFServiceInfo>(userServices.services.values());
} else {
Log.e(TAG, "Failed to persist NFCID2.");
// Undo registration
if (oldDynamicNfcid2 == null) {
userServices.dynamicNfcid2.remove(componentName);
} else {
userServices.dynamicNfcid2.put(componentName, oldDynamicNfcid2);
}
}
}
if (success) {
// Make callback without the lock held
mCallback.onNfcFServicesUpdated(userId, newServices);
}
return success;
}
public String getNfcid2ForService(int userId, int uid, ComponentName componentName) {
if (DBG) Log.d(TAG, "getNfcid2ForService");
NfcFServiceInfo service = getService(userId, componentName);
if (service != null) {
if (service.getUid() != uid) {
Log.e(TAG, "UID mismatch");
return null;
}
return service.getNfcid2();
} else {
Log.e(TAG, "Could not find service " + componentName);
return null;
}
}
public void onHostEmulationActivated() {
if (DBG) Log.d(TAG, "onHostEmulationActivated");
synchronized (mLock) {
mActivated = true;
}
}
public void onHostEmulationDeactivated() {
if (DBG) Log.d(TAG, "onHostEmulationDeactivated");
synchronized (mLock) {
mActivated = false;
}
}
public void onNfcDisabled() {
synchronized (mLock) {
mActivated = false;
}
}
public void onUserSwitched() {
synchronized (mLock) {
mUserSwitched = true;
}
}
private String generateRandomNfcid2() {
long min = 0L;
long max = 0xFFFFFFFFFFFFL;
long randomNfcid2 = (long)Math.floor(Math.random() * (max-min+1)) + min;
return String.format("02FE%02X%02X%02X%02X%02X%02X",
(randomNfcid2 >>> 8 * 5) & 0xFF, (randomNfcid2 >>> 8 * 4) & 0xFF,
(randomNfcid2 >>> 8 * 3) & 0xFF, (randomNfcid2 >>> 8 * 2) & 0xFF,
(randomNfcid2 >>> 8 * 1) & 0xFF, (randomNfcid2 >>> 8 * 0) & 0xFF);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Registered HCE-F services for current user: ");
synchronized (mLock) {
UserServices userServices = findOrCreateUserLocked(ActivityManager.getCurrentUser());
for (NfcFServiceInfo service : userServices.services.values()) {
service.dump(fd, pw, args);
pw.println("");
}
pw.println("");
}
}
}