From 08b7d5270ffdb663ade7a51e2b3933fcd4155723 Mon Sep 17 00:00:00 2001 From: Alisher Alikhodjaev Date: Thu, 15 Dec 2022 14:30:50 -0800 Subject: [PATCH] Implement NfcServiceManager and NfcFrameworkInitializer Bug: 244264995 Test: read a tag, nfc on/off Merged-In: Ie11e888cb852740d806d06c0c725bb2a4544e13c Change-Id: Ie11e888cb852740d806d06c0c725bb2a4544e13c --- boot/preloaded-classes | 2 + core/api/module-lib-current.txt | 24 ++++ core/java/android/app/ActivityThread.java | 3 + .../android/app/SystemServiceRegistry.java | 10 +- core/java/android/nfc/NfcAdapter.java | 21 ++- .../android/nfc/NfcFrameworkInitializer.java | 71 ++++++++++ core/java/android/nfc/NfcServiceManager.java | 126 ++++++++++++++++++ 7 files changed, 242 insertions(+), 15 deletions(-) create mode 100644 core/java/android/nfc/NfcFrameworkInitializer.java create mode 100644 core/java/android/nfc/NfcServiceManager.java diff --git a/boot/preloaded-classes b/boot/preloaded-classes index 9a4e364108ab..19e8dc72e6a3 100644 --- a/boot/preloaded-classes +++ b/boot/preloaded-classes @@ -5416,6 +5416,8 @@ android.nfc.NfcAdapter$CreateNdefMessageCallback android.nfc.NfcAdapter android.nfc.NfcControllerAlwaysOnListener android.nfc.NfcManager +android.nfc.NfcServiceManager$ServiceRegisterer +android.nfc.NfcServiceManager android.nfc.Tag$1 android.nfc.Tag android.nfc.TechListParcel$1 diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 0424ddc1bc5a..c6c4daf7b0ac 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -297,6 +297,30 @@ package android.net.netstats { } +package android.nfc { + + public class NfcFrameworkInitializer { + method public static void registerServiceWrappers(); + method public static void setNfcServiceManager(@NonNull android.nfc.NfcServiceManager); + } + + public class NfcServiceManager { + method @NonNull public android.nfc.NfcServiceManager.ServiceRegisterer getNfcManagerServiceRegisterer(); + } + + public static class NfcServiceManager.ServiceNotFoundException extends java.lang.Exception { + ctor public NfcServiceManager.ServiceNotFoundException(@NonNull String); + } + + public static final class NfcServiceManager.ServiceRegisterer { + method @Nullable public android.os.IBinder get(); + method @NonNull public android.os.IBinder getOrThrow() throws android.nfc.NfcServiceManager.ServiceNotFoundException; + method public void register(@NonNull android.os.IBinder); + method @Nullable public android.os.IBinder tryGet(); + } + +} + package android.os { public final class BatteryStatsManager { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1310b833edf3..14e83d8d75e2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -107,6 +107,8 @@ import android.net.ConnectivityManager; import android.net.Proxy; import android.net.TrafficStats; import android.net.Uri; +import android.nfc.NfcFrameworkInitializer; +import android.nfc.NfcServiceManager; import android.os.AsyncTask; import android.os.Binder; import android.os.BluetoothServiceManager; @@ -7886,6 +7888,7 @@ public final class ActivityThread extends ClientTransactionHandler BluetoothFrameworkInitializer.setBluetoothServiceManager(new BluetoothServiceManager()); BluetoothFrameworkInitializer.setBinderCallsStatsInitializer(context -> { BinderCallsStats.startForBluetooth(context); }); + NfcFrameworkInitializer.setNfcServiceManager(new NfcServiceManager()); } private void purgePendingResources() { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index db1db91752e0..2b8d8ace65b1 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -148,7 +148,7 @@ import android.net.vcn.IVcnManagementService; import android.net.vcn.VcnManager; import android.net.wifi.WifiFrameworkInitializer; import android.net.wifi.nl80211.WifiNl80211Manager; -import android.nfc.NfcManager; +import android.nfc.NfcFrameworkInitializer; import android.ondevicepersonalization.OnDevicePersonalizationFrameworkInitializer; import android.os.BatteryManager; import android.os.BatteryStats; @@ -457,13 +457,6 @@ public final class SystemServiceRegistry { return new BatteryManager(ctx, stats, registrar); }}); - registerService(Context.NFC_SERVICE, NfcManager.class, - new CachedServiceFetcher() { - @Override - public NfcManager createService(ContextImpl ctx) { - return new NfcManager(ctx); - }}); - registerService(Context.DROPBOX_SERVICE, DropBoxManager.class, new CachedServiceFetcher() { @Override @@ -1514,6 +1507,7 @@ public final class SystemServiceRegistry { JobSchedulerFrameworkInitializer.registerServiceWrappers(); BlobStoreManagerFrameworkInitializer.initialize(); BluetoothFrameworkInitializer.registerServiceWrappers(); + NfcFrameworkInitializer.registerServiceWrappers(); TelephonyFrameworkInitializer.registerServiceWrappers(); AppSearchManagerFrameworkInitializer.initialize(); WifiFrameworkInitializer.registerServiceWrappers(); diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 6dc80cf4c374..1bb44af81cec 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -43,7 +43,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; -import android.os.ServiceManager; import android.util.Log; import java.io.IOException; @@ -426,6 +425,7 @@ public final class NfcAdapter { // recovery @UnsupportedAppUsage static INfcAdapter sService; + static NfcServiceManager.ServiceRegisterer sServiceRegisterer; static INfcTag sTagService; static INfcCardEmulation sCardEmulationService; static INfcFCardEmulation sNfcFCardEmulationService; @@ -624,6 +624,12 @@ public final class NfcAdapter { Log.v(TAG, "this device does not have NFC support"); throw new UnsupportedOperationException(); } + NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager(); + if (manager == null) { + Log.e(TAG, "NfcServiceManager is null"); + throw new UnsupportedOperationException(); + } + sServiceRegisterer = manager.getNfcManagerServiceRegisterer(); sService = getServiceInterface(); if (sService == null) { Log.e(TAG, "could not retrieve NFC service"); @@ -665,7 +671,7 @@ public final class NfcAdapter { /** get handle to NFC service interface */ private static INfcAdapter getServiceInterface() { /* get a handle to NFC service */ - IBinder b = ServiceManager.getService("nfc"); + IBinder b = sServiceRegisterer.get(); if (b == null) { return null; } @@ -695,12 +701,13 @@ public final class NfcAdapter { "context not associated with any application (using a mock context?)"); } - if (getServiceInterface() == null) { - // NFC is not available - return null; + if (sIsInitialized && sServiceRegisterer.tryGet() == null) { + synchronized (NfcAdapter.class) { + /* Stale sService pointer */ + if (sIsInitialized) sIsInitialized = false; + } } - - /* use getSystemService() for consistency */ + /* Try to initialize the service */ NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); if (manager == null) { // NFC not available diff --git a/core/java/android/nfc/NfcFrameworkInitializer.java b/core/java/android/nfc/NfcFrameworkInitializer.java new file mode 100644 index 000000000000..1ab8a1ebd72c --- /dev/null +++ b/core/java/android/nfc/NfcFrameworkInitializer.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.nfc; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.content.Context; + +/** + * Class for performing registration for Nfc service. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class NfcFrameworkInitializer { + private NfcFrameworkInitializer() {} + + private static volatile NfcServiceManager sNfcServiceManager; + + /** + * Sets an instance of {@link NfcServiceManager} that allows + * the nfc mainline module to register/obtain nfc binder services. This is called + * by the platform during the system initialization. + * + * @param nfcServiceManager instance of {@link NfcServiceManager} that allows + * the nfc mainline module to register/obtain nfcd binder services. + */ + public static void setNfcServiceManager( + @NonNull NfcServiceManager nfcServiceManager) { + if (sNfcServiceManager != null) { + throw new IllegalStateException("setNfcServiceManager called twice!"); + } + + if (nfcServiceManager == null) { + throw new IllegalArgumentException("nfcServiceManager must not be null"); + } + + sNfcServiceManager = nfcServiceManager; + } + + /** @hide */ + public static NfcServiceManager getNfcServiceManager() { + return sNfcServiceManager; + } + + /** + * Called by {@link SystemServiceRegistry}'s static initializer and registers NFC service + * to {@link Context}, so that {@link Context#getSystemService} can return them. + * + * @throws IllegalStateException if this is called from anywhere besides + * {@link SystemServiceRegistry} + */ + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService(Context.NFC_SERVICE, + NfcManager.class, context -> new NfcManager(context)); + } +} diff --git a/core/java/android/nfc/NfcServiceManager.java b/core/java/android/nfc/NfcServiceManager.java new file mode 100644 index 000000000000..5582f1154cad --- /dev/null +++ b/core/java/android/nfc/NfcServiceManager.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/********************************************************************** + * This file is not a part of the NFC mainline modure * + * *******************************************************************/ + +package android.nfc; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.SystemApi.Client; +import android.content.Context; +import android.os.IBinder; +import android.os.ServiceManager; + +/** + * Provides a way to register and obtain the system service binder objects managed by the nfc + * service. + * + * @hide + */ +@SystemApi(client = Client.MODULE_LIBRARIES) +public class NfcServiceManager { + + /** + * @hide + */ + public NfcServiceManager() { + } + + /** + * A class that exposes the methods to register and obtain each system service. + */ + public static final class ServiceRegisterer { + private final String mServiceName; + + /** + * @hide + */ + public ServiceRegisterer(String serviceName) { + mServiceName = serviceName; + } + + /** + * Register a system server binding object for a service. + */ + public void register(@NonNull IBinder service) { + ServiceManager.addService(mServiceName, service); + } + + /** + * Get the system server binding object for a service. + * + *

This blocks until the service instance is ready, + * or a timeout happens, in which case it returns null. + */ + @Nullable + public IBinder get() { + return ServiceManager.getService(mServiceName); + } + + /** + * Get the system server binding object for a service. + * + *

This blocks until the service instance is ready, + * or a timeout happens, in which case it throws {@link ServiceNotFoundException}. + */ + @NonNull + public IBinder getOrThrow() throws ServiceNotFoundException { + try { + return ServiceManager.getServiceOrThrow(mServiceName); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new ServiceNotFoundException(mServiceName); + } + } + + /** + * Get the system server binding object for a service. If the specified service is + * not available, it returns null. + */ + @Nullable + public IBinder tryGet() { + return ServiceManager.checkService(mServiceName); + } + } + + /** + * See {@link ServiceRegisterer#getOrThrow}. + * + */ + public static class ServiceNotFoundException extends ServiceManager.ServiceNotFoundException { + /** + * Constructor. + * + * @param name the name of the binder service that cannot be found. + * + */ + public ServiceNotFoundException(@NonNull String name) { + super(name); + } + } + + /** + * Returns {@link ServiceRegisterer} for the "nfc" service. + */ + @NonNull + public ServiceRegisterer getNfcManagerServiceRegisterer() { + return new ServiceRegisterer(Context.NFC_SERVICE); + } +}