Make best effort attempt to recover NFC service when it dies.
Retrieve the service again from ServiceManager on RemoteException. Change-Id: Ie227b52019e7deafeab712af1addd6d957f7a8ee Signed-off-by: Nick Pelly <npelly@google.com>
This commit is contained in:
@@ -42,8 +42,8 @@ public class NdefTagConnection extends RawTagConnection {
|
|||||||
* Internal constructor, to be used by NfcAdapter
|
* Internal constructor, to be used by NfcAdapter
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
/* package private */ NdefTagConnection(INfcAdapter service, NdefTag tag, String target) throws RemoteException {
|
/* package private */ NdefTagConnection(NfcAdapter adapter, NdefTag tag, String target) throws RemoteException {
|
||||||
super(service, tag);
|
super(adapter, tag);
|
||||||
String[] targets = tag.getNdefTargets();
|
String[] targets = tag.getNdefTargets();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -63,8 +63,8 @@ public class NdefTagConnection extends RawTagConnection {
|
|||||||
* Internal constructor, to be used by NfcAdapter
|
* Internal constructor, to be used by NfcAdapter
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
/* package private */ NdefTagConnection(INfcAdapter service, NdefTag tag) throws RemoteException {
|
/* package private */ NdefTagConnection(NfcAdapter adapter, NdefTag tag) throws RemoteException {
|
||||||
this(service, tag, tag.getNdefTargets()[0]);
|
this(adapter, tag, tag.getNdefTargets()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,7 +97,7 @@ public class NdefTagConnection extends RawTagConnection {
|
|||||||
msgArray[0] = msg;
|
msgArray[0] = msg;
|
||||||
return msgArray;
|
return msgArray;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died");
|
attemptDeadServiceRecovery(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ public class NdefTagConnection extends RawTagConnection {
|
|||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died");
|
attemptDeadServiceRecovery(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ public class NdefTagConnection extends RawTagConnection {
|
|||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died");
|
attemptDeadServiceRecovery(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ public class NdefTagConnection extends RawTagConnection {
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died");
|
attemptDeadServiceRecovery(e);
|
||||||
return NDEF_MODE_UNKNOWN;
|
return NDEF_MODE_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,10 @@ public final class NfcAdapter {
|
|||||||
private static boolean sIsInitialized = false;
|
private static boolean sIsInitialized = false;
|
||||||
private static NfcAdapter sAdapter;
|
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) {
|
private NfcAdapter(INfcAdapter service) {
|
||||||
mService = 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.
|
* Get a handle to the default NFC Adapter on this Android device.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -214,18 +227,31 @@ public final class NfcAdapter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a handle to NFC service */
|
INfcAdapter service = getServiceInterface();
|
||||||
IBinder b = ServiceManager.getService("nfc");
|
if (service == null) {
|
||||||
if (b == null) {
|
|
||||||
Log.e(TAG, "could not retrieve NFC service");
|
Log.e(TAG, "could not retrieve NFC service");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
sAdapter = new NfcAdapter(INfcAdapter.Stub.asInterface(b));
|
sAdapter = new NfcAdapter(service);
|
||||||
return sAdapter;
|
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.
|
* Return true if this NFC Adapter has any features enabled.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -241,7 +267,7 @@ public final class NfcAdapter {
|
|||||||
try {
|
try {
|
||||||
return mService.isEnabled();
|
return mService.isEnabled();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException in isEnabled()", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +284,7 @@ public final class NfcAdapter {
|
|||||||
try {
|
try {
|
||||||
return mService.enable();
|
return mService.enable();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException in enable()", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +303,7 @@ public final class NfcAdapter {
|
|||||||
try {
|
try {
|
||||||
return mService.disable();
|
return mService.disable();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException in disable()", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,7 +329,7 @@ public final class NfcAdapter {
|
|||||||
try {
|
try {
|
||||||
mService.localSet(message);
|
mService.localSet(message);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +343,7 @@ public final class NfcAdapter {
|
|||||||
try {
|
try {
|
||||||
return mService.localGet();
|
return mService.localGet();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,9 +357,9 @@ public final class NfcAdapter {
|
|||||||
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new RawTagConnection(mService, tag);
|
return new RawTagConnection(this, tag);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,9 +373,9 @@ public final class NfcAdapter {
|
|||||||
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new RawTagConnection(mService, tag, target);
|
return new RawTagConnection(this, tag, target);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,9 +389,9 @@ public final class NfcAdapter {
|
|||||||
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new NdefTagConnection(mService, tag);
|
return new NdefTagConnection(this, tag);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,9 +405,9 @@ public final class NfcAdapter {
|
|||||||
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
throw new IllegalArgumentException("mock tag cannot be used for connections");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new NdefTagConnection(mService, tag, target);
|
return new NdefTagConnection(this, tag, target);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,15 +35,20 @@ import android.util.Log;
|
|||||||
*/
|
*/
|
||||||
public class RawTagConnection {
|
public class RawTagConnection {
|
||||||
|
|
||||||
/*package*/ final INfcAdapter mService;
|
|
||||||
/*package*/ final INfcTag mTagService;
|
|
||||||
/*package*/ final Tag mTag;
|
/*package*/ final Tag mTag;
|
||||||
/*package*/ boolean mIsConnected;
|
/*package*/ boolean mIsConnected;
|
||||||
/*package*/ String mSelectedTarget;
|
/*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";
|
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();
|
String[] targets = tag.getRawTargets();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -58,14 +63,28 @@ public class RawTagConnection {
|
|||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
mService = service;
|
mAdapter = adapter;
|
||||||
mTagService = service.getNfcTagInterface();
|
mService = mAdapter.mService;
|
||||||
|
mTagService = mService.getNfcTagInterface();
|
||||||
mTag = tag;
|
mTag = tag;
|
||||||
mSelectedTarget = target;
|
mSelectedTarget = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package private */ RawTagConnection(INfcAdapter service, Tag tag) throws RemoteException {
|
/*package*/ RawTagConnection(NfcAdapter adapter, Tag tag) throws RemoteException {
|
||||||
this(service, tag, tag.getRawTargets()[0]);
|
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 {
|
try {
|
||||||
return mTagService.isPresent(mTag.mServiceHandle);
|
return mTagService.isPresent(mTag.mServiceHandle);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +155,7 @@ public class RawTagConnection {
|
|||||||
try {
|
try {
|
||||||
mTagService.close(mTag.mServiceHandle);
|
mTagService.close(mTag.mServiceHandle);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +178,7 @@ public class RawTagConnection {
|
|||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "NFC service died", e);
|
attemptDeadServiceRecovery(e);
|
||||||
throw new IOException("NFC service died");
|
throw new IOException("NFC service died");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user