1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.nfc;
18 
19 import android.annotation.NonNull;
20 import android.app.ActivityManager;
21 import android.app.backup.BackupManager;
22 import android.content.ApexEnvironment;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.nfc.Constants;
26 import android.nfc.NfcFrameworkInitializer;
27 import android.nfc.NfcServiceManager;
28 import android.os.Handler;
29 import android.os.HandlerThread;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.RemoteException;
33 import android.os.SystemClock;
34 import android.os.SystemProperties;
35 import android.os.UserHandle;
36 import android.os.VibrationEffect;
37 import android.provider.Settings;
38 import android.se.omapi.ISecureElementService;
39 import android.se.omapi.SeFrameworkInitializer;
40 import android.se.omapi.SeServiceManager;
41 import android.text.TextUtils;
42 import android.util.AtomicFile;
43 import android.util.Log;
44 
45 import com.android.nfc.cardemulation.util.StatsdUtils;
46 import com.android.nfc.dhimpl.NativeNfcManager;
47 import com.android.nfc.flags.FeatureFlags;
48 import com.android.nfc.handover.HandoverDataParser;
49 import com.android.nfc.proto.NfcEventProto;
50 
51 import java.io.File;
52 import java.time.LocalDateTime;
53 
54 /**
55  * To be used for dependency injection (especially helps mocking static dependencies).
56  * TODO: Migrate more classes to injector to resolve circular dependencies in the NFC stack.
57  */
58 public class NfcInjector {
59     private static final String TAG = "NfcInjector";
60     private static final String APEX_NAME = "com.android.nfcservices";
61     private static final String NFC_DATA_DIR = "/data/nfc";
62     private static final String EVENT_LOG_FILE_NAME = "event_log.binpb";
63 
64     private final Context mContext;
65     private final Looper mMainLooper;
66     private final NfcEventLog mNfcEventLog;
67     private final RoutingTableParser mRoutingTableParser;
68     private final ScreenStateHelper mScreenStateHelper;
69     private final NfcUnlockManager mNfcUnlockManager;
70     private final HandoverDataParser mHandoverDataParser;
71     private final DeviceConfigFacade mDeviceConfigFacade;
72     private final NfcDispatcher mNfcDispatcher;
73     private final VibrationEffect mVibrationEffect;
74     private final BackupManager mBackupManager;
75     private final FeatureFlags mFeatureFlags;
76     private final StatsdUtils mStatsdUtils;
77     private final ForegroundUtils mForegroundUtils;
78     private final NfcDiagnostics mNfcDiagnostics;
79     private final NfcServiceManager.ServiceRegisterer mNfcManagerRegisterer;
80     private static NfcInjector sInstance;
81 
getInstance()82     public static NfcInjector getInstance() {
83         if (sInstance == null) throw new IllegalStateException("Nfc injector instance null");
84         return sInstance;
85     }
86 
87 
NfcInjector(@onNull Context context, @NonNull Looper mainLooper)88     public NfcInjector(@NonNull Context context, @NonNull Looper mainLooper) {
89         if (sInstance != null) throw new IllegalStateException("Nfc injector instance not null");
90 
91         mContext = context;
92         mMainLooper = mainLooper;
93         mRoutingTableParser = new RoutingTableParser();
94         mScreenStateHelper = new ScreenStateHelper(mContext);
95         mNfcUnlockManager = NfcUnlockManager.getInstance();
96         mHandoverDataParser = new HandoverDataParser();
97         mDeviceConfigFacade = new DeviceConfigFacade(mContext, new Handler(mainLooper));
98         mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, isInProvisionMode());
99         mVibrationEffect = VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE);
100         mBackupManager = new BackupManager(mContext);
101         mFeatureFlags = new com.android.nfc.flags.FeatureFlagsImpl();
102         mStatsdUtils = mFeatureFlags.statsdCeEventsFlag() ? new StatsdUtils() : null;
103         mForegroundUtils =
104                 ForegroundUtils.getInstance(mContext.getSystemService(ActivityManager.class));
105         mNfcDiagnostics = new NfcDiagnostics(mContext);
106 
107         NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager();
108         if (manager == null) {
109             Log.e(TAG, "NfcServiceManager is null");
110             throw new UnsupportedOperationException();
111         }
112         mNfcManagerRegisterer = manager.getNfcManagerServiceRegisterer();
113 
114         // Create UWB event log thread.
115         HandlerThread eventLogThread = new HandlerThread("NfcEventLog");
116         eventLogThread.start();
117         mNfcEventLog = new NfcEventLog(mContext, this, eventLogThread.getLooper(),
118                 new AtomicFile(new File(NFC_DATA_DIR, EVENT_LOG_FILE_NAME)));
119         sInstance = this;
120     }
121 
getContext()122     public Context getContext() {
123         return mContext;
124     }
125 
getMainLooper()126     public Looper getMainLooper() {
127         return mMainLooper;
128     }
129 
getNfcEventLog()130     public NfcEventLog getNfcEventLog() {
131         return mNfcEventLog;
132     }
133 
getScreenStateHelper()134     public ScreenStateHelper getScreenStateHelper() {
135         return mScreenStateHelper;
136     }
137 
getRoutingTableParser()138     public RoutingTableParser getRoutingTableParser() {
139         return mRoutingTableParser;
140     }
141 
getNfcUnlockManager()142     public NfcUnlockManager getNfcUnlockManager() {
143         return mNfcUnlockManager;
144     }
145 
getHandoverDataParser()146     public HandoverDataParser getHandoverDataParser() {
147         return mHandoverDataParser;
148     }
149 
getDeviceConfigFacade()150     public DeviceConfigFacade getDeviceConfigFacade() {
151         return mDeviceConfigFacade;
152     }
153 
getNfcDispatcher()154     public NfcDispatcher getNfcDispatcher() {
155         return mNfcDispatcher;
156     }
157 
getVibrationEffect()158     public VibrationEffect getVibrationEffect() {
159         return mVibrationEffect;
160     }
161 
getBackupManager()162     public BackupManager getBackupManager() {
163         return mBackupManager;
164     }
165 
getFeatureFlags()166     public FeatureFlags getFeatureFlags() {
167         return mFeatureFlags;
168     }
169 
getStatsdUtils()170     public StatsdUtils getStatsdUtils() {
171         return mStatsdUtils;
172     }
173 
getForegroundUtils()174     public ForegroundUtils getForegroundUtils() {
175         return mForegroundUtils;
176     }
177 
getNfcDiagnostics()178     public NfcDiagnostics getNfcDiagnostics() {
179         return mNfcDiagnostics;
180     }
181 
getNfcManagerRegisterer()182     public NfcServiceManager.ServiceRegisterer getNfcManagerRegisterer() {
183         return mNfcManagerRegisterer;
184     }
185 
makeDeviceHost(DeviceHost.DeviceHostListener listener)186     public DeviceHost makeDeviceHost(DeviceHost.DeviceHostListener listener) {
187         return new NativeNfcManager(mContext, listener);
188     }
189 
190     /**
191      * NFC apex DE folder.
192      */
getDeviceProtectedDataDir()193     public static File getDeviceProtectedDataDir() {
194         return ApexEnvironment.getApexEnvironment(APEX_NAME)
195                 .getDeviceProtectedDataDir();
196     }
197 
getLocalDateTime()198     public LocalDateTime getLocalDateTime() {
199         return LocalDateTime.now();
200     }
201 
isInProvisionMode()202     public boolean isInProvisionMode() {
203         boolean isNfcProvisioningEnabled = false;
204         try {
205             isNfcProvisioningEnabled = mContext.getResources().getBoolean(
206                     R.bool.enable_nfc_provisioning);
207         } catch (Resources.NotFoundException e) {
208         }
209 
210         if (isNfcProvisioningEnabled) {
211             return Settings.Global.getInt(mContext.getContentResolver(),
212                     Settings.Global.DEVICE_PROVISIONED, 0) == 0;
213         } else {
214             return false;
215         }
216     }
217 
checkIsSecureNfcCapable()218     public boolean checkIsSecureNfcCapable() {
219         if (mContext.getResources().getBoolean(R.bool.enable_secure_nfc_support)) {
220             return true;
221         }
222         String[] skuList = mContext.getResources().getStringArray(
223                 R.array.config_skuSupportsSecureNfc);
224         String sku = SystemProperties.get("ro.boot.hardware.sku");
225         if (TextUtils.isEmpty(sku) || !Utils.arrayContains(skuList, sku)) {
226             return false;
227         }
228         return true;
229     }
230 
connectToSeService()231     public ISecureElementService connectToSeService() throws RemoteException {
232         SeServiceManager manager = SeFrameworkInitializer.getSeServiceManager();
233         if (manager == null) {
234             Log.e(TAG, "SEServiceManager is null");
235             return null;
236         }
237         return ISecureElementService.Stub.asInterface(
238                 manager.getSeManagerServiceRegisterer().get());
239     }
240 
241     /**
242      * Kill the NFC stack.
243      */
killNfcStack()244     public void killNfcStack() {
245         System.exit(0);
246     }
247 
isSatelliteModeSensitive()248     public boolean isSatelliteModeSensitive() {
249         final String satelliteRadios =
250                 Settings.Global.getString(mContext.getContentResolver(),
251                         Constants.SETTINGS_SATELLITE_MODE_RADIOS);
252         return satelliteRadios == null || satelliteRadios.contains(Settings.Global.RADIO_NFC);
253     }
254 
255     /** Returns true if satellite mode is turned on. */
isSatelliteModeOn()256     public boolean isSatelliteModeOn() {
257         if (!isSatelliteModeSensitive()) return false;
258         return Settings.Global.getInt(
259                 mContext.getContentResolver(), Constants.SETTINGS_SATELLITE_MODE_ENABLED, 0) == 1;
260     }
261 
262     /**
263      * Get the current time of the clock in milliseconds.
264      *
265      * @return Current time in milliseconds.
266      */
getWallClockMillis()267     public long getWallClockMillis() {
268         return System.currentTimeMillis();
269     }
270 
271     /**
272      * Returns milliseconds since boot, including time spent in sleep.
273      *
274      * @return Current time since boot in milliseconds.
275      */
getElapsedSinceBootMillis()276     public long getElapsedSinceBootMillis() {
277         return SystemClock.elapsedRealtime();
278     }
279 
280     /**
281      * Returns nanoseconds since boot, including time spent in sleep.
282      *
283      * @return Current time since boot in milliseconds.
284      */
getElapsedSinceBootNanos()285     public long getElapsedSinceBootNanos() {
286         return SystemClock.elapsedRealtimeNanos();
287     }
288 }