summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/nfc/NdefTagConnection.java16
-rw-r--r--core/java/android/nfc/NfcAdapter.java62
-rw-r--r--core/java/android/nfc/RawTagConnection.java39
3 files changed, 81 insertions, 36 deletions
diff --git a/core/java/android/nfc/NdefTagConnection.java b/core/java/android/nfc/NdefTagConnection.java
index 321b0ec..27fa25c 100644
--- a/core/java/android/nfc/NdefTagConnection.java
+++ b/core/java/android/nfc/NdefTagConnection.java
@@ -42,8 +42,8 @@ public class NdefTagConnection extends RawTagConnection {
* Internal constructor, to be used by NfcAdapter
* @hide
*/
- /* package private */ NdefTagConnection(INfcAdapter service, NdefTag tag, String target) throws RemoteException {
- super(service, tag);
+ /* package private */ NdefTagConnection(NfcAdapter adapter, NdefTag tag, String target) throws RemoteException {
+ super(adapter, tag);
String[] targets = tag.getNdefTargets();
int i;
@@ -63,8 +63,8 @@ public class NdefTagConnection extends RawTagConnection {
* Internal constructor, to be used by NfcAdapter
* @hide
*/
- /* package private */ NdefTagConnection(INfcAdapter service, NdefTag tag) throws RemoteException {
- this(service, tag, tag.getNdefTargets()[0]);
+ /* package private */ NdefTagConnection(NfcAdapter adapter, NdefTag tag) throws RemoteException {
+ this(adapter, tag, tag.getNdefTargets()[0]);
}
/**
@@ -97,7 +97,7 @@ public class NdefTagConnection extends RawTagConnection {
msgArray[0] = msg;
return msgArray;
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died");
+ attemptDeadServiceRecovery(e);
return null;
}
}
@@ -134,7 +134,7 @@ public class NdefTagConnection extends RawTagConnection {
throw new IOException();
}
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died");
+ attemptDeadServiceRecovery(e);
}
}
@@ -161,7 +161,7 @@ public class NdefTagConnection extends RawTagConnection {
throw new IOException();
}
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died");
+ attemptDeadServiceRecovery(e);
return false;
}
}
@@ -188,7 +188,7 @@ public class NdefTagConnection extends RawTagConnection {
return result;
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died");
+ attemptDeadServiceRecovery(e);
return NDEF_MODE_UNKNOWN;
}
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 7f4b4a2..a093d12 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -168,7 +168,10 @@ public final class NfcAdapter {
private static boolean sIsInitialized = false;
private static NfcAdapter sAdapter;
- private final INfcAdapter mService;
+ // Final after construction, except for attemptDeadServiceRecovery()
+ // when NFC crashes.
+ // Not locked - we accept a best effort attempt when NFC crashes.
+ /*package*/ INfcAdapter mService;
private NfcAdapter(INfcAdapter service) {
mService = service;
@@ -194,6 +197,16 @@ public final class NfcAdapter {
}
}
+ /** get handle to NFC service interface */
+ private static synchronized INfcAdapter getServiceInterface() {
+ /* get a handle to NFC service */
+ IBinder b = ServiceManager.getService("nfc");
+ if (b == null) {
+ return null;
+ }
+ return INfcAdapter.Stub.asInterface(b);
+ }
+
/**
* Get a handle to the default NFC Adapter on this Android device.
* <p>
@@ -214,18 +227,31 @@ public final class NfcAdapter {
return null;
}
- /* get a handle to NFC service */
- IBinder b = ServiceManager.getService("nfc");
- if (b == null) {
+ INfcAdapter service = getServiceInterface();
+ if (service == null) {
Log.e(TAG, "could not retrieve NFC service");
return null;
}
- sAdapter = new NfcAdapter(INfcAdapter.Stub.asInterface(b));
+ sAdapter = new NfcAdapter(service);
return sAdapter;
}
}
+ /** NFC service dead - attempt best effort recovery */
+ /*package*/ void attemptDeadServiceRecovery(Exception e) {
+ Log.e(TAG, "NFC service dead - attempting to recover", e);
+ INfcAdapter service = getServiceInterface();
+ if (service == null) {
+ Log.e(TAG, "could not retrieve NFC service during service recovery");
+ return;
+ }
+ /* assigning to mService is not thread-safe, but this is best-effort code
+ * and on a well-behaved system should never happen */
+ mService = service;
+ return;
+ }
+
/**
* Return true if this NFC Adapter has any features enabled.
* <p>
@@ -241,7 +267,7 @@ public final class NfcAdapter {
try {
return mService.isEnabled();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in isEnabled()", e);
+ attemptDeadServiceRecovery(e);
return false;
}
}
@@ -258,7 +284,7 @@ public final class NfcAdapter {
try {
return mService.enable();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in enable()", e);
+ attemptDeadServiceRecovery(e);
return false;
}
}
@@ -277,7 +303,7 @@ public final class NfcAdapter {
try {
return mService.disable();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in disable()", e);
+ attemptDeadServiceRecovery(e);
return false;
}
}
@@ -303,7 +329,7 @@ public final class NfcAdapter {
try {
mService.localSet(message);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
}
}
@@ -317,7 +343,7 @@ public final class NfcAdapter {
try {
return mService.localGet();
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
return null;
}
}
@@ -331,9 +357,9 @@ public final class NfcAdapter {
throw new IllegalArgumentException("mock tag cannot be used for connections");
}
try {
- return new RawTagConnection(mService, tag);
+ return new RawTagConnection(this, tag);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
return null;
}
}
@@ -347,9 +373,9 @@ public final class NfcAdapter {
throw new IllegalArgumentException("mock tag cannot be used for connections");
}
try {
- return new RawTagConnection(mService, tag, target);
+ return new RawTagConnection(this, tag, target);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
return null;
}
}
@@ -363,9 +389,9 @@ public final class NfcAdapter {
throw new IllegalArgumentException("mock tag cannot be used for connections");
}
try {
- return new NdefTagConnection(mService, tag);
+ return new NdefTagConnection(this, tag);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
return null;
}
}
@@ -379,9 +405,9 @@ public final class NfcAdapter {
throw new IllegalArgumentException("mock tag cannot be used for connections");
}
try {
- return new NdefTagConnection(mService, tag, target);
+ return new NdefTagConnection(this, tag, target);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
return null;
}
}
diff --git a/core/java/android/nfc/RawTagConnection.java b/core/java/android/nfc/RawTagConnection.java
index 8442893..24072e5 100644
--- a/core/java/android/nfc/RawTagConnection.java
+++ b/core/java/android/nfc/RawTagConnection.java
@@ -35,15 +35,20 @@ import android.util.Log;
*/
public class RawTagConnection {
- /*package*/ final INfcAdapter mService;
- /*package*/ final INfcTag mTagService;
/*package*/ final Tag mTag;
/*package*/ boolean mIsConnected;
/*package*/ String mSelectedTarget;
+ private final NfcAdapter mAdapter;
+
+ // Following fields are final after construction, except for
+ // during attemptDeadServiceRecovery() when NFC crashes.
+ // Not locked - we accept a best effort attempt when NFC crashes.
+ /*package*/ INfcAdapter mService;
+ /*package*/ INfcTag mTagService;
private static final String TAG = "NFC";
- /* package private */ RawTagConnection(INfcAdapter service, Tag tag, String target) throws RemoteException {
+ /*package*/ RawTagConnection(NfcAdapter adapter, Tag tag, String target) throws RemoteException {
String[] targets = tag.getRawTargets();
int i;
@@ -58,14 +63,28 @@ public class RawTagConnection {
throw new IllegalArgumentException();
}
- mService = service;
- mTagService = service.getNfcTagInterface();
+ mAdapter = adapter;
+ mService = mAdapter.mService;
+ mTagService = mService.getNfcTagInterface();
mTag = tag;
mSelectedTarget = target;
}
- /* package private */ RawTagConnection(INfcAdapter service, Tag tag) throws RemoteException {
- this(service, tag, tag.getRawTargets()[0]);
+ /*package*/ RawTagConnection(NfcAdapter adapter, Tag tag) throws RemoteException {
+ this(adapter, tag, tag.getRawTargets()[0]);
+ }
+
+ /** NFC service dead - attempt best effort recovery */
+ /*package*/ void attemptDeadServiceRecovery(Exception e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ /* assigning to mService is not thread-safe, but this is best-effort code
+ * and on a well-behaved system should never happen */
+ mService = mAdapter.mService;
+ try {
+ mTagService = mService.getNfcTagInterface();
+ } catch (RemoteException e2) {
+ Log.e(TAG, "second RemoteException trying to recover from dead NFC service", e2);
+ }
}
/**
@@ -101,7 +120,7 @@ public class RawTagConnection {
try {
return mTagService.isPresent(mTag.mServiceHandle);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
return false;
}
}
@@ -136,7 +155,7 @@ public class RawTagConnection {
try {
mTagService.close(mTag.mServiceHandle);
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
}
}
@@ -159,7 +178,7 @@ public class RawTagConnection {
}
return response;
} catch (RemoteException e) {
- Log.e(TAG, "NFC service died", e);
+ attemptDeadServiceRecovery(e);
throw new IOException("NFC service died");
}
}