From 6d55e1342fc35c26dd97700ae791b34668266018 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Wed, 27 Oct 2010 01:14:43 -0700 Subject: 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 --- core/java/android/nfc/NdefTagConnection.java | 16 +++---- core/java/android/nfc/NfcAdapter.java | 62 ++++++++++++++++++++-------- core/java/android/nfc/RawTagConnection.java | 39 ++++++++++++----- 3 files changed, 81 insertions(+), 36 deletions(-) (limited to 'core/java/android/nfc') 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. *

@@ -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. *

@@ -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"); } } -- cgit v1.1