Add a mechanism to register AIDs to specific off-host SE
Test: manual Bug: 117253962 Change-Id: Id34bf84dcff7789548eac19478010838bebd9758
This commit is contained in:
@@ -29253,8 +29253,10 @@ package android.nfc.cardemulation {
|
||||
method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
|
||||
method public boolean registerAidsForService(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
|
||||
method public boolean removeAidsForService(android.content.ComponentName, java.lang.String);
|
||||
method public boolean setOffHostForService(android.content.ComponentName, java.lang.String);
|
||||
method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
|
||||
method public boolean supportsAidPrefixRegistration();
|
||||
method public boolean unsetOffHostForService(android.content.ComponentName);
|
||||
method public boolean unsetPreferredService(android.app.Activity);
|
||||
field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
|
||||
field public static final java.lang.String CATEGORY_OTHER = "other";
|
||||
|
||||
@@ -31,6 +31,8 @@ interface INfcCardEmulation
|
||||
boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
|
||||
boolean setDefaultForNextTap(int userHandle, in ComponentName service);
|
||||
boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
|
||||
boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
|
||||
boolean unsetOffHostForService(int userHandle, in ComponentName service);
|
||||
AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
|
||||
boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
|
||||
List<ApduServiceInfo> getServices(int userHandle, in String category);
|
||||
|
||||
@@ -18,11 +18,10 @@ package android.nfc.cardemulation;
|
||||
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.TypedArray;
|
||||
@@ -30,7 +29,6 @@ import android.content.res.XmlResourceParser;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
@@ -68,6 +66,18 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
*/
|
||||
final boolean mOnHost;
|
||||
|
||||
/**
|
||||
* Offhost reader name.
|
||||
* eg: SIM, eSE etc
|
||||
*/
|
||||
String mOffHostName;
|
||||
|
||||
/**
|
||||
* Offhost reader name from manifest file.
|
||||
* Used for unsetOffHostSecureElement()
|
||||
*/
|
||||
final String mStaticOffHostName;
|
||||
|
||||
/**
|
||||
* Mapping from category to static AID group
|
||||
*/
|
||||
@@ -104,15 +114,17 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
|
||||
public ApduServiceInfo(ResolveInfo info, String description,
|
||||
ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
|
||||
boolean requiresUnlock, int bannerResource, int uid,
|
||||
String settingsActivityName) {
|
||||
String settingsActivityName, String offHost, String staticOffHost) {
|
||||
this.mService = info;
|
||||
this.mDescription = description;
|
||||
this.mStaticAidGroups = new HashMap<String, AidGroup>();
|
||||
this.mDynamicAidGroups = new HashMap<String, AidGroup>();
|
||||
this.mOnHost = onHost;
|
||||
this.mOffHostName = offHost;
|
||||
this.mStaticOffHostName = staticOffHost;
|
||||
this.mOnHost = (offHost == null);
|
||||
this.mRequiresDeviceUnlock = requiresUnlock;
|
||||
for (AidGroup aidGroup : staticAidGroups) {
|
||||
this.mStaticAidGroups.put(aidGroup.category, aidGroup);
|
||||
@@ -174,6 +186,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
|
||||
mSettingsActivityName = sa.getString(
|
||||
com.android.internal.R.styleable.HostApduService_settingsActivity);
|
||||
mOffHostName = null;
|
||||
mStaticOffHostName = mOffHostName;
|
||||
sa.recycle();
|
||||
} else {
|
||||
TypedArray sa = res.obtainAttributes(attrs,
|
||||
@@ -186,6 +200,16 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
|
||||
mSettingsActivityName = sa.getString(
|
||||
com.android.internal.R.styleable.HostApduService_settingsActivity);
|
||||
mOffHostName = sa.getString(
|
||||
com.android.internal.R.styleable.OffHostApduService_secureElementName);
|
||||
if (mOffHostName != null) {
|
||||
if (mOffHostName.equals("eSE")) {
|
||||
mOffHostName = "eSE1";
|
||||
} else if (mOffHostName.equals("SIM")) {
|
||||
mOffHostName = "SIM1";
|
||||
}
|
||||
}
|
||||
mStaticOffHostName = mOffHostName;
|
||||
sa.recycle();
|
||||
}
|
||||
|
||||
@@ -289,6 +313,10 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mService.serviceInfo.name);
|
||||
}
|
||||
|
||||
public String getOffHostSecureElement() {
|
||||
return mOffHostName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a consolidated list of AIDs from the AID groups
|
||||
* registered by this service. Note that if a service has both
|
||||
@@ -404,6 +432,20 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public void setOffHostSecureElement(String offHost) {
|
||||
mOffHostName = offHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the off host Secure Element to statically defined
|
||||
* by the service in the manifest file.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void unsetOffHostSecureElement() {
|
||||
mOffHostName = mStaticOffHostName;
|
||||
}
|
||||
|
||||
public CharSequence loadLabel(PackageManager pm) {
|
||||
return mService.loadLabel(pm);
|
||||
}
|
||||
@@ -481,6 +523,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mService.writeToParcel(dest, flags);
|
||||
dest.writeString(mDescription);
|
||||
dest.writeInt(mOnHost ? 1 : 0);
|
||||
dest.writeString(mOffHostName);
|
||||
dest.writeString(mStaticOffHostName);
|
||||
dest.writeInt(mStaticAidGroups.size());
|
||||
if (mStaticAidGroups.size() > 0) {
|
||||
dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
|
||||
@@ -503,6 +547,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
|
||||
String description = source.readString();
|
||||
boolean onHost = source.readInt() != 0;
|
||||
String offHostName = source.readString();
|
||||
String staticOffHostName = source.readString();
|
||||
ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
|
||||
int numStaticGroups = source.readInt();
|
||||
if (numStaticGroups > 0) {
|
||||
@@ -517,9 +563,9 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
int bannerResource = source.readInt();
|
||||
int uid = source.readInt();
|
||||
String settingsActivityName = source.readString();
|
||||
return new ApduServiceInfo(info, onHost, description, staticAidGroups,
|
||||
return new ApduServiceInfo(info, description, staticAidGroups,
|
||||
dynamicAidGroups, requiresUnlock, bannerResource, uid,
|
||||
settingsActivityName);
|
||||
settingsActivityName, offHostName, staticOffHostName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -531,6 +577,14 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(" " + getComponent() +
|
||||
" (Description: " + getDescription() + ")");
|
||||
if (mOnHost) {
|
||||
pw.println(" On Host Service");
|
||||
} else {
|
||||
pw.println(" Off-host Service");
|
||||
pw.println(" " + "Current off-host SE" + mOffHostName
|
||||
+ " static off-host: " + mOffHostName);
|
||||
}
|
||||
pw.println(" Static off-host Secure Element:");
|
||||
pw.println(" Static AID groups:");
|
||||
for (AidGroup group : mStaticAidGroups.values()) {
|
||||
pw.println(" Category: " + group.category);
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.content.pm.PackageManager;
|
||||
import android.nfc.INfcCardEmulation;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.util.Log;
|
||||
@@ -344,6 +343,108 @@ public final class CardEmulation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the off-host Secure Element for the given service.
|
||||
*
|
||||
* <p>Note that this will only remove Secure Element that was dynamically
|
||||
* set using the {@link #setOffHostForService(ComponentName, String)}
|
||||
* and resets it to a value that was statically assigned using manifest.
|
||||
*
|
||||
* <p>Note that you can only unset off-host SE for a service that
|
||||
* is running under the same UID as the caller of this API. Typically
|
||||
* this means you need to call this from the same
|
||||
* package as the service itself, though UIDs can also
|
||||
* be shared between packages using shared UIDs.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @return whether the registration was successful.
|
||||
*/
|
||||
public boolean unsetOffHostForService(ComponentName service) {
|
||||
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
|
||||
if (adapter == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return sService.unsetOffHostForService(mContext.getUserId(), service);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.unsetOffHostForService(mContext.getUserId(), service);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the off-host Secure Element for the given service.
|
||||
*
|
||||
* <p>If off-host SE was initially set (either statically
|
||||
* through the manifest, or dynamically by using this API),
|
||||
* it will be replaced with this one. All AIDs registered by
|
||||
* this service will be re-routed to this Secure Element if
|
||||
* successful.
|
||||
*
|
||||
* <p>Note that you can only set off-host SE for a service that
|
||||
* is running under the same UID as the caller of this API. Typically
|
||||
* this means you need to call this from the same
|
||||
* package as the service itself, though UIDs can also
|
||||
* be shared between packages using shared UIDs.
|
||||
*
|
||||
* <p>Registeration will be successful only if the Secure Element
|
||||
* exists on the device.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param offHostSecureElement Secure Element to register the AID to
|
||||
* @return whether the registration was successful.
|
||||
*/
|
||||
public boolean setOffHostForService(ComponentName service, String offHostSecureElement) {
|
||||
boolean validSecureElement = false;
|
||||
|
||||
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
|
||||
if (adapter == null || offHostSecureElement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> validSE = adapter.getSupportedOffHostSecureElements();
|
||||
if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
|
||||
|| (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offHostSecureElement.equals("eSE")) {
|
||||
offHostSecureElement = "eSE1";
|
||||
} else if (offHostSecureElement.equals("SIM")) {
|
||||
offHostSecureElement = "SIM1";
|
||||
}
|
||||
|
||||
try {
|
||||
return sService.setOffHostForService(mContext.getUserId(), service,
|
||||
offHostSecureElement);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.setOffHostForService(mContext.getUserId(), service,
|
||||
offHostSecureElement);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the currently registered AIDs for the specified
|
||||
* category for a service.
|
||||
|
||||
@@ -3690,6 +3690,8 @@
|
||||
<!-- Component name of an activity that allows the user to modify
|
||||
the settings for this service. -->
|
||||
<attr name="settingsActivity"/>
|
||||
<!-- Secure Element which the AIDs should be routed to -->
|
||||
<attr name="secureElementName"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Specify one or more <code>aid-group</code> elements inside a
|
||||
|
||||
Reference in New Issue
Block a user