/* * Copyright (C) 2024 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 com.android.nfc; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.backup.BackupManager; import android.content.ApexEnvironment; import android.content.Context; import android.content.res.Resources; import android.nfc.Constants; import android.nfc.NfcFrameworkInitializer; import android.nfc.NfcServiceManager; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.VibrationEffect; import android.provider.Settings; import android.se.omapi.ISecureElementService; import android.se.omapi.SeFrameworkInitializer; import android.se.omapi.SeServiceManager; import android.text.TextUtils; import android.util.AtomicFile; import android.util.Log; import com.android.nfc.cardemulation.util.StatsdUtils; import com.android.nfc.dhimpl.NativeNfcManager; import com.android.nfc.flags.FeatureFlags; import com.android.nfc.handover.HandoverDataParser; import com.android.nfc.proto.NfcEventProto; import java.io.File; import java.time.LocalDateTime; /** * To be used for dependency injection (especially helps mocking static dependencies). * TODO: Migrate more classes to injector to resolve circular dependencies in the NFC stack. */ public class NfcInjector { private static final String TAG = "NfcInjector"; private static final String APEX_NAME = "com.android.nfcservices"; private static final String NFC_DATA_DIR = "/data/nfc"; private static final String EVENT_LOG_FILE_NAME = "event_log.binpb"; private final Context mContext; private final Looper mMainLooper; private final NfcEventLog mNfcEventLog; private final RoutingTableParser mRoutingTableParser; private final ScreenStateHelper mScreenStateHelper; private final NfcUnlockManager mNfcUnlockManager; private final HandoverDataParser mHandoverDataParser; private final DeviceConfigFacade mDeviceConfigFacade; private final NfcDispatcher mNfcDispatcher; private final VibrationEffect mVibrationEffect; private final BackupManager mBackupManager; private final FeatureFlags mFeatureFlags; private final StatsdUtils mStatsdUtils; private final ForegroundUtils mForegroundUtils; private final NfcDiagnostics mNfcDiagnostics; private final NfcServiceManager.ServiceRegisterer mNfcManagerRegisterer; private static NfcInjector sInstance; public static NfcInjector getInstance() { if (sInstance == null) throw new IllegalStateException("Nfc injector instance null"); return sInstance; } public NfcInjector(@NonNull Context context, @NonNull Looper mainLooper) { if (sInstance != null) throw new IllegalStateException("Nfc injector instance not null"); mContext = context; mMainLooper = mainLooper; mRoutingTableParser = new RoutingTableParser(); mScreenStateHelper = new ScreenStateHelper(mContext); mNfcUnlockManager = NfcUnlockManager.getInstance(); mHandoverDataParser = new HandoverDataParser(); mDeviceConfigFacade = new DeviceConfigFacade(mContext, new Handler(mainLooper)); mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, isInProvisionMode()); mVibrationEffect = VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE); mBackupManager = new BackupManager(mContext); mFeatureFlags = new com.android.nfc.flags.FeatureFlagsImpl(); mStatsdUtils = mFeatureFlags.statsdCeEventsFlag() ? new StatsdUtils() : null; mForegroundUtils = ForegroundUtils.getInstance(mContext.getSystemService(ActivityManager.class)); mNfcDiagnostics = new NfcDiagnostics(mContext); NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager(); if (manager == null) { Log.e(TAG, "NfcServiceManager is null"); throw new UnsupportedOperationException(); } mNfcManagerRegisterer = manager.getNfcManagerServiceRegisterer(); // Create UWB event log thread. HandlerThread eventLogThread = new HandlerThread("NfcEventLog"); eventLogThread.start(); mNfcEventLog = new NfcEventLog(mContext, this, eventLogThread.getLooper(), new AtomicFile(new File(NFC_DATA_DIR, EVENT_LOG_FILE_NAME))); sInstance = this; } public Context getContext() { return mContext; } public Looper getMainLooper() { return mMainLooper; } public NfcEventLog getNfcEventLog() { return mNfcEventLog; } public ScreenStateHelper getScreenStateHelper() { return mScreenStateHelper; } public RoutingTableParser getRoutingTableParser() { return mRoutingTableParser; } public NfcUnlockManager getNfcUnlockManager() { return mNfcUnlockManager; } public HandoverDataParser getHandoverDataParser() { return mHandoverDataParser; } public DeviceConfigFacade getDeviceConfigFacade() { return mDeviceConfigFacade; } public NfcDispatcher getNfcDispatcher() { return mNfcDispatcher; } public VibrationEffect getVibrationEffect() { return mVibrationEffect; } public BackupManager getBackupManager() { return mBackupManager; } public FeatureFlags getFeatureFlags() { return mFeatureFlags; } public StatsdUtils getStatsdUtils() { return mStatsdUtils; } public ForegroundUtils getForegroundUtils() { return mForegroundUtils; } public NfcDiagnostics getNfcDiagnostics() { return mNfcDiagnostics; } public NfcServiceManager.ServiceRegisterer getNfcManagerRegisterer() { return mNfcManagerRegisterer; } public DeviceHost makeDeviceHost(DeviceHost.DeviceHostListener listener) { return new NativeNfcManager(mContext, listener); } /** * NFC apex DE folder. */ public static File getDeviceProtectedDataDir() { return ApexEnvironment.getApexEnvironment(APEX_NAME) .getDeviceProtectedDataDir(); } public LocalDateTime getLocalDateTime() { return LocalDateTime.now(); } public boolean isInProvisionMode() { boolean isNfcProvisioningEnabled = false; try { isNfcProvisioningEnabled = mContext.getResources().getBoolean( R.bool.enable_nfc_provisioning); } catch (Resources.NotFoundException e) { } if (isNfcProvisioningEnabled) { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 0; } else { return false; } } public boolean checkIsSecureNfcCapable() { if (mContext.getResources().getBoolean(R.bool.enable_secure_nfc_support)) { return true; } String[] skuList = mContext.getResources().getStringArray( R.array.config_skuSupportsSecureNfc); String sku = SystemProperties.get("ro.boot.hardware.sku"); if (TextUtils.isEmpty(sku) || !Utils.arrayContains(skuList, sku)) { return false; } return true; } public ISecureElementService connectToSeService() throws RemoteException { SeServiceManager manager = SeFrameworkInitializer.getSeServiceManager(); if (manager == null) { Log.e(TAG, "SEServiceManager is null"); return null; } return ISecureElementService.Stub.asInterface( manager.getSeManagerServiceRegisterer().get()); } /** * Kill the NFC stack. */ public void killNfcStack() { System.exit(0); } public boolean isSatelliteModeSensitive() { final String satelliteRadios = Settings.Global.getString(mContext.getContentResolver(), Constants.SETTINGS_SATELLITE_MODE_RADIOS); return satelliteRadios == null || satelliteRadios.contains(Settings.Global.RADIO_NFC); } /** Returns true if satellite mode is turned on. */ public boolean isSatelliteModeOn() { if (!isSatelliteModeSensitive()) return false; return Settings.Global.getInt( mContext.getContentResolver(), Constants.SETTINGS_SATELLITE_MODE_ENABLED, 0) == 1; } /** * Get the current time of the clock in milliseconds. * * @return Current time in milliseconds. */ public long getWallClockMillis() { return System.currentTimeMillis(); } /** * Returns milliseconds since boot, including time spent in sleep. * * @return Current time since boot in milliseconds. */ public long getElapsedSinceBootMillis() { return SystemClock.elapsedRealtime(); } /** * Returns nanoseconds since boot, including time spent in sleep. * * @return Current time since boot in milliseconds. */ public long getElapsedSinceBootNanos() { return SystemClock.elapsedRealtimeNanos(); } }