Skip to content

Commit bb951c8

Browse files
jhamNick Pelly
authored andcommitted
Changes for access control.
The package name is now required when using the NFC extras APIs so the context is stored away and used to derive the package name to be sent to the NfcService. Bug: 4515759 Change-Id: I1a3aba3fc026e0090a914b0686fc4b8dec25b927
1 parent de62d9c commit bb951c8

File tree

6 files changed

+107
-73
lines changed

6 files changed

+107
-73
lines changed

core/java/android/nfc/INfcAdapter.aidl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import android.nfc.INfcTag;
3232
interface INfcAdapter
3333
{
3434
INfcTag getNfcTagInterface();
35-
INfcAdapterExtras getNfcAdapterExtrasInterface();
35+
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
3636

3737
int getState();
3838
boolean disable();

core/java/android/nfc/INfcAdapterExtras.aidl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ import android.os.Bundle;
2323
* {@hide}
2424
*/
2525
interface INfcAdapterExtras {
26-
Bundle open(IBinder b);
27-
Bundle close();
28-
Bundle transceive(in byte[] data_in);
29-
int getCardEmulationRoute();
30-
void setCardEmulationRoute(int route);
31-
void authenticate(in byte[] token);
26+
Bundle open(in String pkg, IBinder b);
27+
Bundle close(in String pkg, IBinder b);
28+
Bundle transceive(in String pkg, in byte[] data_in);
29+
int getCardEmulationRoute(in String pkg);
30+
void setCardEmulationRoute(in String pkg, int route);
31+
void authenticate(in String pkg, in byte[] token);
3232
}

core/java/android/nfc/NfcAdapter.java

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package android.nfc;
1818

19+
import java.util.HashMap;
20+
1921
import android.annotation.SdkConstant;
2022
import android.annotation.SdkConstant.SdkConstantType;
2123
import android.app.Activity;
@@ -197,15 +199,21 @@ public final class NfcAdapter {
197199
static INfcTag sTagService;
198200

199201
/**
200-
* NfcAdapter is currently a singleton, and does not require a context.
201-
* However all the public API's are future-proofed to require a context.
202-
* If we start using that then we'll need to keep a HashMap of
203-
* Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter
204-
* is a singleton within each application context.
202+
* The NfcAdapter object for each application context.
203+
* There is a 1-1 relationship between application context and
204+
* NfcAdapter object.
205+
*/
206+
static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
207+
208+
/**
209+
* NfcAdapter used with a null context. This ctor was deprecated but we have
210+
* to support it for backwards compatibility. New methods that require context
211+
* might throw when called on the null-context NfcAdapter.
205212
*/
206-
static NfcAdapter sSingleton; // protected by NfcAdapter.class
213+
static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class
207214

208215
final NfcActivityManager mNfcActivityManager;
216+
final Context mContext;
209217

210218
/**
211219
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
@@ -280,12 +288,12 @@ private static boolean hasNfcFeature() {
280288
}
281289

282290
/**
283-
* Returns the singleton, or throws if NFC is not available.
291+
* Returns the NfcAdapter for application context,
292+
* or throws if NFC is not available.
293+
* @hide
284294
*/
285-
static synchronized NfcAdapter getSingleton() {
295+
public static synchronized NfcAdapter getNfcAdapter(Context context) {
286296
if (!sIsInitialized) {
287-
sIsInitialized = true;
288-
289297
/* is this device meant to have NFC */
290298
if (!hasNfcFeature()) {
291299
Log.v(TAG, "this device does not have NFC support");
@@ -303,12 +311,21 @@ static synchronized NfcAdapter getSingleton() {
303311
Log.e(TAG, "could not retrieve NFC Tag service");
304312
throw new UnsupportedOperationException();
305313
}
306-
sSingleton = new NfcAdapter();
314+
315+
sIsInitialized = true;
316+
}
317+
if (context == null) {
318+
if (sNullContextNfcAdapter == null) {
319+
sNullContextNfcAdapter = new NfcAdapter(null);
320+
}
321+
return sNullContextNfcAdapter;
307322
}
308-
if (sSingleton == null) {
309-
throw new UnsupportedOperationException();
323+
NfcAdapter adapter = sNfcAdapters.get(context);
324+
if (adapter == null) {
325+
adapter = new NfcAdapter(context);
326+
sNfcAdapters.put(context, adapter);
310327
}
311-
return sSingleton;
328+
return adapter;
312329
}
313330

314331
/** get handle to NFC service interface */
@@ -336,32 +353,41 @@ private static INfcAdapter getServiceInterface() {
336353
* @return the default NFC adapter, or null if no NFC adapter exists
337354
*/
338355
public static NfcAdapter getDefaultAdapter(Context context) {
356+
if (context == null) {
357+
throw new IllegalArgumentException("context cannot be null");
358+
}
359+
context = context.getApplicationContext();
339360
/* use getSystemService() instead of just instantiating to take
340361
* advantage of the context's cached NfcManager & NfcAdapter */
341362
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
342363
return manager.getDefaultAdapter();
343364
}
344365

345366
/**
346-
* Get a handle to the default NFC Adapter on this Android device.
347-
* <p>
348-
* Most Android devices will only have one NFC Adapter (NFC Controller).
349-
*
350-
* @return the default NFC adapter, or null if no NFC adapter exists
367+
* Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
368+
* This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
369+
* for many NFC API methods. Those methods will fail when called on an NfcAdapter
370+
* object created from this method.<p>
351371
* @deprecated use {@link #getDefaultAdapter(Context)}
352372
*/
353373
@Deprecated
354374
public static NfcAdapter getDefaultAdapter() {
355375
Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
356376
"NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
357-
return getSingleton();
377+
378+
return NfcAdapter.getNfcAdapter(null);
379+
}
380+
381+
NfcAdapter(Context context) {
382+
mContext = context;
383+
mNfcActivityManager = new NfcActivityManager(this);
358384
}
359385

360386
/**
361-
* Does not currently need a context.
387+
* @hide
362388
*/
363-
NfcAdapter() {
364-
mNfcActivityManager = new NfcActivityManager(this);
389+
public Context getContext() {
390+
return mContext;
365391
}
366392

367393
/**
@@ -875,8 +901,12 @@ public boolean isNdefPushEnabled() {
875901
* @hide
876902
*/
877903
public INfcAdapterExtras getNfcAdapterExtrasInterface() {
904+
if (mContext == null) {
905+
throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
906+
+ " NFC extras APIs");
907+
}
878908
try {
879-
return sService.getNfcAdapterExtrasInterface();
909+
return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
880910
} catch (RemoteException e) {
881911
attemptDeadServiceRecovery(e);
882912
return null;

core/java/android/nfc/NfcManager.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ public final class NfcManager {
3939
*/
4040
public NfcManager(Context context) {
4141
NfcAdapter adapter;
42+
context = context.getApplicationContext();
4243
try {
43-
adapter = NfcAdapter.getSingleton();
44+
adapter = NfcAdapter.getNfcAdapter(context);
4445
} catch (UnsupportedOperationException e) {
4546
adapter = null;
4647
}

nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
package com.android.nfc_extras;
1818

19-
import android.annotation.SdkConstant;
20-
import android.annotation.SdkConstant.SdkConstantType;
19+
import android.content.Context;
2120
import android.nfc.INfcAdapterExtras;
2221
import android.nfc.NfcAdapter;
2322
import android.os.RemoteException;
@@ -60,10 +59,14 @@ public final class NfcAdapterExtras {
6059
// best effort recovery
6160
private static NfcAdapter sAdapter;
6261
private static INfcAdapterExtras sService;
63-
private static NfcAdapterExtras sSingleton;
64-
private static NfcExecutionEnvironment sEmbeddedEe;
65-
private static CardEmulationRoute sRouteOff;
66-
private static CardEmulationRoute sRouteOnWhenScreenOn;
62+
private static final CardEmulationRoute ROUTE_OFF =
63+
new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
64+
65+
private final NfcExecutionEnvironment mEmbeddedEe;
66+
private final CardEmulationRoute mRouteOnWhenScreenOn;
67+
68+
final Context mContext;
69+
final String mPackageName;
6770

6871
/** get service handles */
6972
private static void initService() {
@@ -84,31 +87,35 @@ private static void initService() {
8487
* @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
8588
*/
8689
public static NfcAdapterExtras get(NfcAdapter adapter) {
87-
synchronized(NfcAdapterExtras.class) {
88-
if (sSingleton == null) {
90+
Context context = adapter.getContext();
91+
if (context == null) {
92+
throw new UnsupportedOperationException(
93+
"You must pass a context to your NfcAdapter to use the NFC extras APIs");
94+
}
95+
96+
synchronized (NfcAdapterExtras.class) {
97+
if (sService == null) {
8998
try {
9099
sAdapter = adapter;
91-
sSingleton = new NfcAdapterExtras();
92-
sEmbeddedEe = new NfcExecutionEnvironment(sSingleton);
93-
sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
94-
sRouteOnWhenScreenOn = new CardEmulationRoute(
95-
CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
96100
initService();
97101
} finally {
98102
if (sService == null) {
99-
sRouteOnWhenScreenOn = null;
100-
sRouteOff = null;
101-
sEmbeddedEe = null;
102-
sSingleton = null;
103103
sAdapter = null;
104104
}
105105
}
106106
}
107-
return sSingleton;
108107
}
108+
109+
return new NfcAdapterExtras(context);
109110
}
110111

111-
private NfcAdapterExtras() {}
112+
private NfcAdapterExtras(Context context) {
113+
mContext = context.getApplicationContext();
114+
mPackageName = context.getPackageName();
115+
mEmbeddedEe = new NfcExecutionEnvironment(this);
116+
mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON,
117+
mEmbeddedEe);
118+
}
112119

113120
/**
114121
* Immutable data class that describes a card emulation route.
@@ -166,18 +173,16 @@ INfcAdapterExtras getService() {
166173
*
167174
* <p class="note">
168175
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
169-
*
170-
* @return
171176
*/
172177
public CardEmulationRoute getCardEmulationRoute() {
173178
try {
174-
int route = sService.getCardEmulationRoute();
179+
int route = sService.getCardEmulationRoute(mPackageName);
175180
return route == CardEmulationRoute.ROUTE_OFF ?
176-
sRouteOff :
177-
sRouteOnWhenScreenOn;
181+
ROUTE_OFF :
182+
mRouteOnWhenScreenOn;
178183
} catch (RemoteException e) {
179184
attemptDeadServiceRecovery(e);
180-
return sRouteOff;
185+
return ROUTE_OFF;
181186
}
182187
}
183188

@@ -189,27 +194,27 @@ public CardEmulationRoute getCardEmulationRoute() {
189194
* <p class="note">
190195
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
191196
*
192-
* @param route a {@link #CardEmulationRoute}
197+
* @param route a {@link CardEmulationRoute}
193198
*/
194199
public void setCardEmulationRoute(CardEmulationRoute route) {
195200
try {
196-
sService.setCardEmulationRoute(route.route);
201+
sService.setCardEmulationRoute(mPackageName, route.route);
197202
} catch (RemoteException e) {
198203
attemptDeadServiceRecovery(e);
199204
}
200205
}
201206

202207
/**
203208
* Get the {@link NfcExecutionEnvironment} that is embedded with the
204-
* {@link NFcAdapter}.
209+
* {@link NfcAdapter}.
205210
*
206211
* <p class="note">
207212
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
208213
*
209214
* @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
210215
*/
211216
public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
212-
return sEmbeddedEe;
217+
return mEmbeddedEe;
213218
}
214219

215220
/**
@@ -218,12 +223,12 @@ public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
218223
* Some implementations of NFC Adapter Extras may require applications
219224
* to authenticate with a token, before using other methods.
220225
*
221-
* @param a implementation specific token
222-
* @throws a {@link java.lang.SecurityException} if authentication failed
226+
* @param token a implementation specific token
227+
* @throws java.lang.SecurityException if authentication failed
223228
*/
224229
public void authenticate(byte[] token) {
225230
try {
226-
sService.authenticate(token);
231+
sService.authenticate(mPackageName, token);
227232
} catch (RemoteException e) {
228233
attemptDeadServiceRecovery(e);
229234
}

nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,17 @@
1616

1717
package com.android.nfc_extras;
1818

19-
import java.io.IOException;
20-
2119
import android.annotation.SdkConstant;
2220
import android.annotation.SdkConstant.SdkConstantType;
23-
import android.content.Context;
24-
import android.nfc.INfcAdapterExtras;
25-
import android.nfc.NfcAdapter;
2621
import android.os.Binder;
2722
import android.os.Bundle;
28-
import android.os.IBinder;
2923
import android.os.RemoteException;
3024

25+
import java.io.IOException;
26+
3127
public class NfcExecutionEnvironment {
3228
private final NfcAdapterExtras mExtras;
29+
private final Binder mToken;
3330

3431
/**
3532
* Broadcast Action: An ISO-DEP AID was selected.
@@ -115,6 +112,7 @@ public class NfcExecutionEnvironment {
115112

116113
NfcExecutionEnvironment(NfcAdapterExtras extras) {
117114
mExtras = extras;
115+
mToken = new Binder();
118116
}
119117

120118
/**
@@ -133,7 +131,7 @@ public class NfcExecutionEnvironment {
133131
*/
134132
public void open() throws IOException {
135133
try {
136-
Bundle b = mExtras.getService().open(new Binder());
134+
Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken);
137135
throwBundle(b);
138136
} catch (RemoteException e) {
139137
mExtras.attemptDeadServiceRecovery(e);
@@ -151,7 +149,7 @@ public void open() throws IOException {
151149
*/
152150
public void close() throws IOException {
153151
try {
154-
throwBundle(mExtras.getService().close());
152+
throwBundle(mExtras.getService().close(mExtras.mPackageName, mToken));
155153
} catch (RemoteException e) {
156154
mExtras.attemptDeadServiceRecovery(e);
157155
throw new IOException("NFC Service was dead");
@@ -169,7 +167,7 @@ public void close() throws IOException {
169167
public byte[] transceive(byte[] in) throws IOException {
170168
Bundle b;
171169
try {
172-
b = mExtras.getService().transceive(in);
170+
b = mExtras.getService().transceive(mExtras.mPackageName, in);
173171
} catch (RemoteException e) {
174172
mExtras.attemptDeadServiceRecovery(e);
175173
throw new IOException("NFC Service was dead, need to re-open");

0 commit comments

Comments
 (0)