blob: bb2fa9252974adcf579631b35cbb6688c598b88f [file] [log] [blame]
nxpandroid64fd68c2015-09-23 16:45:15 +05301/*
2 * Copyright (C) 2013 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 */
nxf500513a018e72019-04-23 17:11:41 +053016/******************************************************************************
17*
18* The original Work has been changed by NXP.
19*
20* Licensed under the Apache License, Version 2.0 (the "License");
21* you may not use this file except in compliance with the License.
22* You may obtain a copy of the License at
23*
24* http://www.apache.org/licenses/LICENSE-2.0
25*
26* Unless required by applicable law or agreed to in writing, software
27* distributed under the License is distributed on an "AS IS" BASIS,
28* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29* See the License for the specific language governing permissions and
30* limitations under the License.
31*
32* Copyright 2018-2019 NXP
33*
34******************************************************************************/
nxpandroid64fd68c2015-09-23 16:45:15 +053035package com.android.nfc.cardemulation;
36
37import org.xmlpull.v1.XmlPullParser;
38import org.xmlpull.v1.XmlPullParserException;
39import org.xmlpull.v1.XmlSerializer;
40
41import android.app.ActivityManager;
42import android.content.BroadcastReceiver;
43import android.content.ComponentName;
44import android.content.Context;
45import android.content.Intent;
46import android.content.IntentFilter;
47import android.content.pm.PackageManager;
48import android.content.pm.ResolveInfo;
49import android.content.pm.ServiceInfo;
50import android.content.pm.PackageManager.NameNotFoundException;
51import android.net.Uri;
nxf500513a018e72019-04-23 17:11:41 +053052import android.nfc.cardemulation.NfcAidGroup;
53import android.nfc.cardemulation.NfcApduServiceInfo;
nxpandroid64fd68c2015-09-23 16:45:15 +053054import android.nfc.cardemulation.AidGroup;
nxpandroid64fd68c2015-09-23 16:45:15 +053055import android.nfc.cardemulation.CardEmulation;
56import android.nfc.cardemulation.HostApduService;
57import android.nfc.cardemulation.OffHostApduService;
58import android.os.UserHandle;
59import android.util.AtomicFile;
60import android.util.Log;
61import android.util.SparseArray;
62import android.util.Xml;
nxf500513a018e72019-04-23 17:11:41 +053063import com.nxp.nfc.NfcConstants;
nxpandroid64fd68c2015-09-23 16:45:15 +053064
65import com.android.internal.util.FastXmlSerializer;
66import com.google.android.collect.Maps;
67
68import java.io.File;
69import java.io.FileDescriptor;
70import java.io.FileInputStream;
71import java.io.FileOutputStream;
72import java.io.IOException;
73import java.io.PrintWriter;
74import java.util.ArrayList;
75import java.util.Collections;
76import java.util.HashMap;
77import java.util.Iterator;
78import java.util.List;
79import java.util.Map;
80import java.util.concurrent.atomic.AtomicReference;
nxpandroida9a68ba2016-01-14 21:12:17 +053081import com.android.nfc.NfcService;
nxf500513a018e72019-04-23 17:11:41 +053082import android.os.SystemProperties;
nxpandroid64fd68c2015-09-23 16:45:15 +053083
84/**
85 * This class is inspired by android.content.pm.RegisteredServicesCache
86 * That class was not re-used because it doesn't support dynamically
87 * registering additional properties, but generates everything from
88 * the manifest. Since we have some properties that are not in the manifest,
89 * it's less suited.
90 */
91public class RegisteredServicesCache {
92 static final String XML_INDENT_OUTPUT_FEATURE = "http://xmlpull.org/v1/doc/features.html#indent-output";
93 static final String TAG = "RegisteredServicesCache";
nxf500514ff9f422019-03-20 16:28:16 +053094 static final boolean DEBUG =
nxf500513a018e72019-04-23 17:11:41 +053095 ((SystemProperties.get("persist.nfc.ce_debug").equals("1")) ? true : false);
nxpandroid34627bd2016-05-27 15:52:30 +053096 static final String SERVICE_STATE_FILE_VERSION="1.0";
nxpandroid64fd68c2015-09-23 16:45:15 +053097
98 final Context mContext;
99 final AtomicReference<BroadcastReceiver> mReceiver;
100
101 final Object mLock = new Object();
102 // All variables below synchronized on mLock
103
104 // mUserServices holds the card emulation services that are running for each user
105 final SparseArray<UserServices> mUserServices = new SparseArray<UserServices>();
106 final Callback mCallback;
nxf500513a018e72019-04-23 17:11:41 +0530107 final AtomicFile mDynamicSettingsFile;
nxpandroida9a68ba2016-01-14 21:12:17 +0530108 final AtomicFile mServiceStateFile;
nxf500513a018e72019-04-23 17:11:41 +0530109 final HashMap<ComponentName, NfcApduServiceInfo> mAllServices = Maps.newHashMap();
nxpandroidfc2aab82017-04-10 18:19:30 +0530110 HashMap<String, HashMap<ComponentName, Integer>> installedServices = new HashMap<>();
nxpandroid64fd68c2015-09-23 16:45:15 +0530111
nxpandroid64fd68c2015-09-23 16:45:15 +0530112 public interface Callback {
nxf500513a018e72019-04-23 17:11:41 +0530113 void onServicesUpdated(int userId, final List<NfcApduServiceInfo> services);
nxpandroid64fd68c2015-09-23 16:45:15 +0530114 };
115
nxf500513a018e72019-04-23 17:11:41 +0530116 static class DynamicSettings {
nxpandroid64fd68c2015-09-23 16:45:15 +0530117 public final int uid;
nxf500513a018e72019-04-23 17:11:41 +0530118 public final HashMap<String, NfcAidGroup> aidGroups = Maps.newHashMap();
119 public String offHostSE;
nxpandroid64fd68c2015-09-23 16:45:15 +0530120
nxf500513a018e72019-04-23 17:11:41 +0530121 DynamicSettings(int uid) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530122 this.uid = uid;
123 }
124 };
125
126 private static class UserServices {
127 /**
128 * All services that have registered
129 */
nxf500513a018e72019-04-23 17:11:41 +0530130 final HashMap<ComponentName, NfcApduServiceInfo> services =
nxpandroid64fd68c2015-09-23 16:45:15 +0530131 Maps.newHashMap(); // Re-built at run-time
nxf500513a018e72019-04-23 17:11:41 +0530132 final HashMap<ComponentName, DynamicSettings> dynamicSettings =
133 Maps.newHashMap(); // In memory cache of dynamic Setting store
nxpandroid64fd68c2015-09-23 16:45:15 +0530134 };
135
136 private UserServices findOrCreateUserLocked(int userId) {
137 UserServices services = mUserServices.get(userId);
138 if (services == null) {
139 services = new UserServices();
140 mUserServices.put(userId, services);
141 }
142 return services;
143 }
144
145 public RegisteredServicesCache(Context context, Callback callback) {
146 mContext = context;
147 mCallback = callback;
148
149 final BroadcastReceiver receiver = new BroadcastReceiver() {
150 @Override
151 public void onReceive(Context context, Intent intent) {
152 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
153 String action = intent.getAction();
154 if (DEBUG) Log.d(TAG, "Intent action: " + action);
155 if (uid != -1) {
nxpandroid5d64ce92016-11-18 19:48:53 +0530156 int currentUser = ActivityManager.getCurrentUser();
157 if (currentUser == UserHandle.getUserId(uid)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530158 if(Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
159 Uri uri = intent.getData();
160 String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
nxpandroid64fd68c2015-09-23 16:45:15 +0530161 }
nxpandroid5d64ce92016-11-18 19:48:53 +0530162 boolean replaced = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) &&
163 (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
164 Intent.ACTION_PACKAGE_REMOVED.equals(action));
165 if (!replaced) {
166 invalidateCache(UserHandle.getUserId(uid));
nxpandroid64fd68c2015-09-23 16:45:15 +0530167 } else {
nxf500513a018e72019-04-23 17:11:41 +0530168 // Cache will automatically be updated on user switch
169 if (DEBUG) Log.d(TAG, " Not removing service here " + replaced);
nxpandroid64fd68c2015-09-23 16:45:15 +0530170 }
171 } else {
nxf500513a018e72019-04-23 17:11:41 +0530172 if (DEBUG) Log.d(TAG, "Ignoring package intent due to package being replaced.");
nxpandroid64fd68c2015-09-23 16:45:15 +0530173 }
174 }
175 }
176 };
177 mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
178
179 IntentFilter intentFilter = new IntentFilter();
180 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
181 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
182 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
183 intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
184 intentFilter.addAction(Intent.ACTION_PACKAGE_FIRST_LAUNCH);
185 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
186 intentFilter.addDataScheme("package");
187 mContext.registerReceiverAsUser(mReceiver.get(), UserHandle.ALL, intentFilter, null, null);
188
189 // Register for events related to sdcard operations
190 IntentFilter sdFilter = new IntentFilter();
191 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
192 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
193 mContext.registerReceiverAsUser(mReceiver.get(), UserHandle.ALL, sdFilter, null, null);
194
195 File dataDir = mContext.getFilesDir();
nxf500513a018e72019-04-23 17:11:41 +0530196 mDynamicSettingsFile = new AtomicFile(new File(dataDir, "dynamic_aids.xml"));
nxpandroida9a68ba2016-01-14 21:12:17 +0530197 mServiceStateFile = new AtomicFile(new File(dataDir, "service_state.xml"));
nxpandroid64fd68c2015-09-23 16:45:15 +0530198 }
199
nxf500513a018e72019-04-23 17:11:41 +0530200 void dump(ArrayList<NfcApduServiceInfo> services) {
201 for (NfcApduServiceInfo service : services) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530202 if (DEBUG) Log.d(TAG, service.toString());
203 }
204 }
205
nxf500513a018e72019-04-23 17:11:41 +0530206 boolean containsServiceLocked(ArrayList<NfcApduServiceInfo> services, ComponentName serviceName) {
207 for (NfcApduServiceInfo service : services) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530208 if (service.getComponent().equals(serviceName)) return true;
209 }
210 return false;
211 }
212
213 public boolean hasService(int userId, ComponentName service) {
214 return getService(userId, service) != null;
215 }
216
nxf500513a018e72019-04-23 17:11:41 +0530217 public NfcApduServiceInfo getService(int userId, ComponentName service) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530218 synchronized (mLock) {
219 UserServices userServices = findOrCreateUserLocked(userId);
220 return userServices.services.get(service);
221 }
222 }
223
nxf500513a018e72019-04-23 17:11:41 +0530224 public List<NfcApduServiceInfo> getServices(int userId) {
225 final ArrayList<NfcApduServiceInfo> services = new ArrayList<NfcApduServiceInfo>();
nxpandroid64fd68c2015-09-23 16:45:15 +0530226 synchronized (mLock) {
227 UserServices userServices = findOrCreateUserLocked(userId);
228 services.addAll(userServices.services.values());
229 }
230 return services;
231 }
232
nxf500513a018e72019-04-23 17:11:41 +0530233 public List<NfcApduServiceInfo> getServicesForCategory(int userId, String category) {
234 final ArrayList<NfcApduServiceInfo> services = new ArrayList<NfcApduServiceInfo>();
nxpandroid64fd68c2015-09-23 16:45:15 +0530235 synchronized (mLock) {
236 UserServices userServices = findOrCreateUserLocked(userId);
nxf500513a018e72019-04-23 17:11:41 +0530237 for (NfcApduServiceInfo service : userServices.services.values()) {
nxpandroidebf53fb2016-12-22 18:48:59 +0530238 if (service.hasCategory(category) &&
239 (service.getAidCacheSizeForCategory(category) > 0)) services.add(service);
nxpandroid64fd68c2015-09-23 16:45:15 +0530240 }
241 }
242 return services;
243 }
244
nxf500513a018e72019-04-23 17:11:41 +0530245 ArrayList<NfcApduServiceInfo> getInstalledServices(int userId) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530246 PackageManager pm;
247 try {
248 pm = mContext.createPackageContextAsUser("android", 0,
249 new UserHandle(userId)).getPackageManager();
250 } catch (NameNotFoundException e) {
251 Log.e(TAG, "Could not create user package context");
252 return null;
253 }
254 mAllServices.clear();
nxf500513a018e72019-04-23 17:11:41 +0530255 ArrayList<NfcApduServiceInfo> validServices = new ArrayList<NfcApduServiceInfo>();
nxpandroid64fd68c2015-09-23 16:45:15 +0530256
nxpandroid3509fde2017-09-14 11:16:20 +0530257 List<ResolveInfo> resolvedServices = new ArrayList<>(pm.queryIntentServicesAsUser(
nxpandroid64fd68c2015-09-23 16:45:15 +0530258 new Intent(HostApduService.SERVICE_INTERFACE),
nxpandroid3509fde2017-09-14 11:16:20 +0530259 PackageManager.GET_META_DATA, userId));
nxpandroid64fd68c2015-09-23 16:45:15 +0530260
261 List<ResolveInfo> resolvedOffHostServices = pm.queryIntentServicesAsUser(
262 new Intent(OffHostApduService.SERVICE_INTERFACE),
263 PackageManager.GET_META_DATA, userId);
264 resolvedServices.addAll(resolvedOffHostServices);
265
266 for (ResolveInfo resolvedService : resolvedServices) {
267 try {
268 boolean onHost = !resolvedOffHostServices.contains(resolvedService);
269 ServiceInfo si = resolvedService.serviceInfo;
270 ComponentName componentName = new ComponentName(si.packageName, si.name);
271 // Check if the package holds the NFC permission
272 if (pm.checkPermission(android.Manifest.permission.NFC, si.packageName) !=
273 PackageManager.PERMISSION_GRANTED) {
nxpandroidf8260a22017-05-12 16:07:09 +0530274 Log.e(TAG, "Skipping application component " + componentName +
275 ": it must request the permission " +
nxpandroid64fd68c2015-09-23 16:45:15 +0530276 android.Manifest.permission.NFC);
277 continue;
278 }
279 if (!android.Manifest.permission.BIND_NFC_SERVICE.equals(
280 si.permission)) {
281 Log.e(TAG, "Skipping APDU service " + componentName +
282 ": it does not require the permission " +
283 android.Manifest.permission.BIND_NFC_SERVICE);
284 continue;
285 }
nxf500513a018e72019-04-23 17:11:41 +0530286 NfcApduServiceInfo service = new NfcApduServiceInfo(pm, resolvedService, onHost);
nxpandroid64fd68c2015-09-23 16:45:15 +0530287 if (service != null) {
288 validServices.add(service);
289 if(!onHost)
290 mAllServices.put(componentName, service);
291 }
292 } catch (XmlPullParserException e) {
293 Log.w(TAG, "Unable to load component info " + resolvedService.toString(), e);
294 } catch (IOException e) {
295 Log.w(TAG, "Unable to load component info " + resolvedService.toString(), e);
296 }
297 }
nxpandroid64fd68c2015-09-23 16:45:15 +0530298 return validServices;
299 }
300
nxf500513a018e72019-04-23 17:11:41 +0530301 public ArrayList<NfcApduServiceInfo> getAllServices() {
302 return new ArrayList<NfcApduServiceInfo>(mAllServices.values());//mAllServices;
nxpandroid64fd68c2015-09-23 16:45:15 +0530303 }
304
nxf500513a018e72019-04-23 17:11:41 +0530305 public HashMap<ComponentName, NfcApduServiceInfo> getAllStaticHashServices() {
nxpandroid64fd68c2015-09-23 16:45:15 +0530306 return mAllServices;
307 }
308
nxpandroid64fd68c2015-09-23 16:45:15 +0530309 public void invalidateCache(int userId) {
nxf500513a018e72019-04-23 17:11:41 +0530310 final ArrayList<NfcApduServiceInfo> validServices = getInstalledServices(userId);
nxpandroid64fd68c2015-09-23 16:45:15 +0530311 if (validServices == null) {
312 return;
313 }
314 synchronized (mLock) {
315 UserServices userServices = findOrCreateUserLocked(userId);
316
317 // Find removed services
nxf500513a018e72019-04-23 17:11:41 +0530318 Iterator<Map.Entry<ComponentName, NfcApduServiceInfo>> it =
nxpandroid64fd68c2015-09-23 16:45:15 +0530319 userServices.services.entrySet().iterator();
320 while (it.hasNext()) {
nxf500513a018e72019-04-23 17:11:41 +0530321 Map.Entry<ComponentName, NfcApduServiceInfo> entry =
322 (Map.Entry<ComponentName, NfcApduServiceInfo>) it.next();
nxpandroid64fd68c2015-09-23 16:45:15 +0530323 if (!containsServiceLocked(validServices, entry.getKey())) {
324 Log.d(TAG, "Service removed: " + entry.getKey());
325 it.remove();
326 }
327 }
nxf500513a018e72019-04-23 17:11:41 +0530328 for (NfcApduServiceInfo service : validServices) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530329 if (DEBUG) Log.d(TAG, "Adding service: " + service.getComponent() +
330 " AIDs: " + service.getAids());
331 userServices.services.put(service.getComponent(), service);
332 }
333
nxf500513a018e72019-04-23 17:11:41 +0530334 // Apply dynamic Setting mappings
nxpandroid64fd68c2015-09-23 16:45:15 +0530335 ArrayList<ComponentName> toBeRemoved = new ArrayList<ComponentName>();
nxf500513a018e72019-04-23 17:11:41 +0530336 for (Map.Entry<ComponentName, DynamicSettings> entry :
337 userServices.dynamicSettings.entrySet()) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530338 // Verify component / uid match
339 ComponentName component = entry.getKey();
nxf500513a018e72019-04-23 17:11:41 +0530340 DynamicSettings dynamicSettings = entry.getValue();
341 NfcApduServiceInfo serviceInfo = userServices.services.get(component);
342 if (serviceInfo == null || (serviceInfo.getUid() != dynamicSettings.uid)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530343 toBeRemoved.add(component);
344 continue;
345 } else {
nxf500513a018e72019-04-23 17:11:41 +0530346 for (NfcAidGroup group : dynamicSettings.aidGroups.values()) {
347 serviceInfo.setOrReplaceDynamicNfcAidGroup(group);
348 }
349 if (dynamicSettings.offHostSE != null) {
350 serviceInfo.setOffHostSecureElement(dynamicSettings.offHostSE);
nxpandroid64fd68c2015-09-23 16:45:15 +0530351 }
352 }
353 }
354
355 if (toBeRemoved.size() > 0) {
356 for (ComponentName component : toBeRemoved) {
nxf500513a018e72019-04-23 17:11:41 +0530357 Log.d(TAG, "Removing dynamic Settings registered by " + component);
358 userServices.dynamicSettings.remove(component);
nxpandroid64fd68c2015-09-23 16:45:15 +0530359 }
360 // Persist to filesystem
nxf500513a018e72019-04-23 17:11:41 +0530361 writeDynamicSettingsLocked();
nxpandroid64fd68c2015-09-23 16:45:15 +0530362 }
nxpandroida9a68ba2016-01-14 21:12:17 +0530363 updateServiceStateFromFile(userId);
nxpandroid34627bd2016-05-27 15:52:30 +0530364 Log.e(TAG,"1"+Thread.currentThread().getStackTrace()[2].getMethodName()+":WriteServiceStateToFile");
nxpandroida9a68ba2016-01-14 21:12:17 +0530365 writeServiceStateToFile(userId);
nxpandroid64fd68c2015-09-23 16:45:15 +0530366 }
367
368 mCallback.onServicesUpdated(userId, Collections.unmodifiableList(validServices));
369 dump(validServices);
370 }
371
nxf500513a018e72019-04-23 17:11:41 +0530372 private void readDynamicSettingsLocked() {
nxpandroid64fd68c2015-09-23 16:45:15 +0530373 FileInputStream fis = null;
374 try {
nxf500513a018e72019-04-23 17:11:41 +0530375 if (!mDynamicSettingsFile.getBaseFile().exists()) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530376 Log.d(TAG, "Dynamic AIDs file does not exist.");
377 return;
378 }
nxf500513a018e72019-04-23 17:11:41 +0530379 fis = mDynamicSettingsFile.openRead();
nxpandroid64fd68c2015-09-23 16:45:15 +0530380 XmlPullParser parser = Xml.newPullParser();
381 parser.setInput(fis, null);
382 int eventType = parser.getEventType();
383 while (eventType != XmlPullParser.START_TAG &&
384 eventType != XmlPullParser.END_DOCUMENT) {
385 eventType = parser.next();
386 }
387 String tagName = parser.getName();
388 if ("services".equals(tagName)) {
389 boolean inService = false;
390 ComponentName currentComponent = null;
391 int currentUid = -1;
nxf500513a018e72019-04-23 17:11:41 +0530392 String currentOffHostSE = null;
393 ArrayList<NfcAidGroup> currentGroups = new ArrayList<NfcAidGroup>();
nxpandroid64fd68c2015-09-23 16:45:15 +0530394 while (eventType != XmlPullParser.END_DOCUMENT) {
395 tagName = parser.getName();
396 if (eventType == XmlPullParser.START_TAG) {
397 if ("service".equals(tagName) && parser.getDepth() == 2) {
398 String compString = parser.getAttributeValue(null, "component");
399 String uidString = parser.getAttributeValue(null, "uid");
nxf500513a018e72019-04-23 17:11:41 +0530400 String offHostString = parser.getAttributeValue(null, "offHostSE");
nxpandroid64fd68c2015-09-23 16:45:15 +0530401 if (compString == null || uidString == null) {
402 Log.e(TAG, "Invalid service attributes");
403 } else {
404 try {
405 currentUid = Integer.parseInt(uidString);
406 currentComponent = ComponentName.unflattenFromString(compString);
nxf500513a018e72019-04-23 17:11:41 +0530407 currentOffHostSE = offHostString;
nxpandroid64fd68c2015-09-23 16:45:15 +0530408 inService = true;
409 } catch (NumberFormatException e) {
410 Log.e(TAG, "Could not parse service uid");
411 }
412 }
413 }
414 if ("aid-group".equals(tagName) && parser.getDepth() == 3 && inService) {
nxf500513a018e72019-04-23 17:11:41 +0530415 NfcAidGroup group = NfcAidGroup.createFromXml(parser);
nxpandroid64fd68c2015-09-23 16:45:15 +0530416 if (group != null) {
417 currentGroups.add(group);
418 } else {
419 Log.e(TAG, "Could not parse AID group.");
420 }
421 }
422 } else if (eventType == XmlPullParser.END_TAG) {
423 if ("service".equals(tagName)) {
424 // See if we have a valid service
425 if (currentComponent != null && currentUid >= 0 &&
nxf500513a018e72019-04-23 17:11:41 +0530426 (currentGroups.size() > 0 || currentOffHostSE != null)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530427 final int userId = UserHandle.getUserId(currentUid);
nxf500513a018e72019-04-23 17:11:41 +0530428 DynamicSettings dynSettings = new DynamicSettings(currentUid);
429 for (NfcAidGroup group : currentGroups) {
430 dynSettings.aidGroups.put(group.getCategory(), group);
nxpandroid64fd68c2015-09-23 16:45:15 +0530431 }
nxf500513a018e72019-04-23 17:11:41 +0530432 dynSettings.offHostSE = currentOffHostSE;
nxpandroid64fd68c2015-09-23 16:45:15 +0530433 UserServices services = findOrCreateUserLocked(userId);
nxf500513a018e72019-04-23 17:11:41 +0530434 services.dynamicSettings.put(currentComponent, dynSettings);
nxpandroid64fd68c2015-09-23 16:45:15 +0530435 }
436 currentUid = -1;
437 currentComponent = null;
438 currentGroups.clear();
439 inService = false;
nxf500513a018e72019-04-23 17:11:41 +0530440 currentOffHostSE = null;
nxpandroid64fd68c2015-09-23 16:45:15 +0530441 }
442 }
443 eventType = parser.next();
444 };
445 }
446 } catch (Exception e) {
nxf500513a018e72019-04-23 17:11:41 +0530447 Log.e(TAG, "Could not parse dynamic Settings file, trashing.");
448 mDynamicSettingsFile.delete();
nxpandroid64fd68c2015-09-23 16:45:15 +0530449 } finally {
450 if (fis != null) {
451 try {
452 fis.close();
453 } catch (IOException e) {
454 }
455 }
456 }
457 }
458
nxf500513a018e72019-04-23 17:11:41 +0530459 private boolean writeDynamicSettingsLocked() {
nxpandroid64fd68c2015-09-23 16:45:15 +0530460 FileOutputStream fos = null;
461 try {
nxf500513a018e72019-04-23 17:11:41 +0530462 fos = mDynamicSettingsFile.startWrite();
nxpandroid64fd68c2015-09-23 16:45:15 +0530463 XmlSerializer out = new FastXmlSerializer();
464 out.setOutput(fos, "utf-8");
465 out.startDocument(null, true);
466 out.setFeature(XML_INDENT_OUTPUT_FEATURE, true);
467 out.startTag(null, "services");
468 for (int i = 0; i < mUserServices.size(); i++) {
469 final UserServices user = mUserServices.valueAt(i);
nxf500513a018e72019-04-23 17:11:41 +0530470 for (Map.Entry<ComponentName, DynamicSettings> service : user.dynamicSettings.entrySet()) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530471 out.startTag(null, "service");
472 out.attribute(null, "component", service.getKey().flattenToString());
473 out.attribute(null, "uid", Integer.toString(service.getValue().uid));
nxf500513a018e72019-04-23 17:11:41 +0530474 if(service.getValue().offHostSE != null) {
475 out.attribute(null, "offHostSE", service.getValue().offHostSE);
476 }
477 for (NfcAidGroup group : service.getValue().aidGroups.values()) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530478 group.writeAsXml(out);
479 }
480 out.endTag(null, "service");
481 }
482 }
483 out.endTag(null, "services");
484 out.endDocument();
nxf500513a018e72019-04-23 17:11:41 +0530485 mDynamicSettingsFile.finishWrite(fos);
nxpandroid64fd68c2015-09-23 16:45:15 +0530486 return true;
487 } catch (Exception e) {
nxf500513a018e72019-04-23 17:11:41 +0530488 Log.e(TAG, "Error writing dynamic Settings", e);
nxpandroid64fd68c2015-09-23 16:45:15 +0530489 if (fos != null) {
nxf500513a018e72019-04-23 17:11:41 +0530490 mDynamicSettingsFile.failWrite(fos);
nxpandroid64fd68c2015-09-23 16:45:15 +0530491 }
492 return false;
493 }
494 }
495
nxpandroida9a68ba2016-01-14 21:12:17 +0530496 private void updateServiceStateFromFile(int currUserId)
497 {
498 FileInputStream fis = null;
499 try {
nxpandroid34627bd2016-05-27 15:52:30 +0530500 /*if(NfcService.getInstance().getAidRoutingTableStatus() == 0x00) {
nxpandroida9a68ba2016-01-14 21:12:17 +0530501 Log.e(TAG, " Aid Routing Table still availble , No need to disable services");
502 return;
nxpandroid34627bd2016-05-27 15:52:30 +0530503 }*/
504 Log.d(TAG, " Reading service state data always from file");
nxpandroida9a68ba2016-01-14 21:12:17 +0530505 if(!mServiceStateFile.getBaseFile().exists()) {
506 Log.d(TAG,"mServiceStateFile does not exist");
507 return;
508 }
509 fis = mServiceStateFile.openRead();
510 XmlPullParser parser = Xml.newPullParser();
511 parser.setInput(fis , null);
512 int eventType = parser.getEventType();
513 int currUid = -1;
514 ComponentName currComponent = null;
nxf500513a018e72019-04-23 17:11:41 +0530515 //HashMap<ComponentName ,NfcApduServiceInfo> nfcOffHostServiceMap = mRegisteredNfcServicesCache.getApduservicesMaps();
516 int state = NfcConstants.SERVICE_STATE_ENABLED;
nxpandroidfc2aab82017-04-10 18:19:30 +0530517
nxpandroida9a68ba2016-01-14 21:12:17 +0530518 while (eventType != XmlPullParser.START_TAG &&
519 eventType != XmlPullParser.END_DOCUMENT) {
520 eventType = parser.next();
521 }
522 String tagName = parser.getName();
nxpandroid34627bd2016-05-27 15:52:30 +0530523 String fileVersion = "null";
524 /**
525 * Get the version of the Service state file.
526 * if the version is 1.0, service states are stored as integers(0,1,2,3)
527 * or else service states are stored as boolean (true or false)
528 */
529 if("Version".equals(tagName)){
530 fileVersion = parser.getAttributeValue(null ,"FileVersion");
531 Log.d(TAG, "ServiceStateFileVersion="+fileVersion);
532 eventType = parser.next();
533 while (eventType != XmlPullParser.START_TAG &&
534 eventType != XmlPullParser.END_DOCUMENT) {
535 eventType = parser.next();
536 }
537 tagName = parser.getName();
538 Log.e(TAG, "Next Tag="+tagName);
539 }
nxpandroida9a68ba2016-01-14 21:12:17 +0530540 if ("services".equals(tagName)) {
541 while (eventType != XmlPullParser.END_DOCUMENT) {
542 tagName = parser.getName();
543 if (eventType == XmlPullParser.START_TAG) {
544 if("service".equals(tagName) && parser.getDepth() == 0x02) {
545 String compString = parser.getAttributeValue(null ,"component");
546 String uidString = parser.getAttributeValue(null ,"uid");
547 String stateString = parser.getAttributeValue(null ,"serviceState");
nxpandroidfc2aab82017-04-10 18:19:30 +0530548
nxpandroida9a68ba2016-01-14 21:12:17 +0530549 if(compString == null || uidString == null || stateString == null) {
550 Log.e(TAG, "Invalid service attributes");
551 } else {
552 try {
553 currUid = Integer.parseInt(uidString);
554 currComponent = ComponentName.unflattenFromString(compString);
555 Log.d(TAG, " curr component "+compString);
556 Log.d(TAG, " curr uid "+uidString);
557 Log.d(TAG, " curr state "+stateString);
nxpandroidfc2aab82017-04-10 18:19:30 +0530558
nxpandroid34627bd2016-05-27 15:52:30 +0530559 if(fileVersion.equals("null")){
560 if(stateString.equalsIgnoreCase("false"))
nxf500513a018e72019-04-23 17:11:41 +0530561 state = NfcConstants.SERVICE_STATE_DISABLED;
nxpandroid34627bd2016-05-27 15:52:30 +0530562 else
nxf500513a018e72019-04-23 17:11:41 +0530563 state = NfcConstants.SERVICE_STATE_ENABLED;
nxpandroid34627bd2016-05-27 15:52:30 +0530564 }else if(fileVersion.equals("1.0")){
565 state = Integer.parseInt(stateString);
nxf500513a018e72019-04-23 17:11:41 +0530566 if(state<NfcConstants.SERVICE_STATE_DISABLED || state > NfcConstants.SERVICE_STATE_DISABLING)
nxpandroid34627bd2016-05-27 15:52:30 +0530567 Log.e(TAG, "Invalid Service state");
568 }
nxpandroidfc2aab82017-04-10 18:19:30 +0530569 /*Load all the servies info into local memory from xml file and
570 *later update the xml file with updated information
571 *This way it can retain previous user's information even after switching to different user
572 * */
573 if(installedServices.containsKey(uidString))
574 {
575 Log.e(TAG, "installedServices contains uidString : " +uidString);
576 HashMap<ComponentName, Integer> componentStates;
577 componentStates = installedServices.get(uidString);
578 componentStates.put(currComponent,state);
579 }else
580 {
581 Log.e(TAG, "installedServices no uidString ");
582 HashMap<ComponentName, Integer> componentStates = new HashMap<>();
583 componentStates.put(currComponent,state);
584 installedServices.put(uidString,componentStates);
585 }
586
nxpandroida9a68ba2016-01-14 21:12:17 +0530587 } catch (NumberFormatException e) {
588 Log.e(TAG, "could not parse the service attributes");
589 }
590 }
591 }
592 } else if (eventType == XmlPullParser.END_TAG) {
593 if("service".equals(tagName)) {
594 final int userId = UserHandle.getUserId(currUid);
nxpandroidfc2aab82017-04-10 18:19:30 +0530595
nxpandroida9a68ba2016-01-14 21:12:17 +0530596 UserServices serviceCache = findOrCreateUserLocked(userId);
nxf500513a018e72019-04-23 17:11:41 +0530597 NfcApduServiceInfo serviceInfo = serviceCache.services.get(currComponent);
nxpandroidfc2aab82017-04-10 18:19:30 +0530598
nxf500513a018e72019-04-23 17:11:41 +0530599 if(serviceInfo != null) {
600 serviceInfo.setServiceState(CardEmulation.CATEGORY_OTHER ,state);
601 }
nxpandroida9a68ba2016-01-14 21:12:17 +0530602 }
603 currUid = -1;
604 currComponent = null;
nxf500513a018e72019-04-23 17:11:41 +0530605 state = NfcConstants.SERVICE_STATE_ENABLED;
nxpandroida9a68ba2016-01-14 21:12:17 +0530606 }
607
608 eventType = parser.next();
609 }
610 }
611 } catch(Exception e) {
612 mServiceStateFile.delete();
nxpandroidfc2aab82017-04-10 18:19:30 +0530613 Log.e(TAG, "could not parse the seriveState file , thrashing the file " + e);
nxpandroida9a68ba2016-01-14 21:12:17 +0530614 } finally {
615 try {
616 if(fis != null) {
617 fis.close();
618 }
619 } catch ( Exception e) {
620 }
621 }
622 }
623
624 private boolean writeServiceStateToFile(int currUserId) {
625 FileOutputStream fos = null;
nxf500513a018e72019-04-23 17:11:41 +0530626 //ArrayList<NfcApduServiceInfo> nfcOffHostServiceCache = mRegisteredNfcServicesCache.getApduservicesList();
nxpandroid34627bd2016-05-27 15:52:30 +0530627 /*if(NfcService.getInstance().getAidRoutingTableStatus() == 0x00) {
nxpandroida9a68ba2016-01-14 21:12:17 +0530628 Log.e(TAG, " Aid Routing Table still availble , No need to disable services");
629 return false;
nxpandroid34627bd2016-05-27 15:52:30 +0530630 }*/
631 Log.e(TAG, " Writing service state Data Always");
nxpandroida9a68ba2016-01-14 21:12:17 +0530632 if(currUserId != ActivityManager.getCurrentUser()) {
633 return false;
634 }
nxf500513a018e72019-04-23 17:11:41 +0530635 int state = NfcConstants.SERVICE_STATE_ENABLED;
nxpandroida9a68ba2016-01-14 21:12:17 +0530636 try {
637 fos = mServiceStateFile.startWrite();
638 XmlSerializer out = new FastXmlSerializer();
639 out.setOutput(fos, "utf-8");
640 out.startDocument(null , true);
641 out.setFeature(XML_INDENT_OUTPUT_FEATURE, true);
nxpandroid34627bd2016-05-27 15:52:30 +0530642 out.startTag(null ,"Version");
643 out.attribute(null, "FileVersion", SERVICE_STATE_FILE_VERSION);
644 out.endTag(null ,"Version");
nxpandroida9a68ba2016-01-14 21:12:17 +0530645 out.startTag(null ,"services");
646 for(int userId = 0; userId < mUserServices.size(); userId++) {
647 final UserServices userServices = mUserServices.valueAt(userId);
nxf500513a018e72019-04-23 17:11:41 +0530648 for (NfcApduServiceInfo serviceInfo : userServices.services.values()) {
nxpandroida9a68ba2016-01-14 21:12:17 +0530649 if(!serviceInfo.hasCategory(CardEmulation.CATEGORY_OTHER)) {
650 continue;
651 }
652 out.startTag(null ,"service");
653 out.attribute(null, "component", serviceInfo.getComponent().flattenToString());
nxpandroid34627bd2016-05-27 15:52:30 +0530654 Log.e(TAG,"component name"+ serviceInfo.getComponent().flattenToString());
nxpandroida9a68ba2016-01-14 21:12:17 +0530655 out.attribute(null, "uid", Integer.toString(serviceInfo.getUid()));
nxpandroidfc2aab82017-04-10 18:19:30 +0530656
657 boolean isServiceInstalled = false;
658 if(installedServices.containsKey(Integer.toString(serviceInfo.getUid()))){
659 HashMap<ComponentName, Integer> componentStates = installedServices.get(Integer.toString(serviceInfo.getUid()));
660 if (componentStates.containsKey(serviceInfo.getComponent())) {
661 state = componentStates.get(serviceInfo.getComponent());
662 componentStates.remove(serviceInfo.getComponent());
663 if(componentStates.isEmpty())
664 {
665 installedServices.remove(Integer.toString(serviceInfo.getUid()));
666 }
667 isServiceInstalled = true;
668 }
669 }
670 if (!isServiceInstalled) {
671 state = serviceInfo.getServiceState(CardEmulation.CATEGORY_OTHER);
672 }
673 out.attribute(null, "serviceState", Integer.toString(state));
nxpandroida9a68ba2016-01-14 21:12:17 +0530674 out.endTag(null, "service");
675 }
676 }
nxpandroida9a68ba2016-01-14 21:12:17 +0530677 out.endTag(null ,"services");
678 out.endDocument();
679 mServiceStateFile.finishWrite(fos);
680 return true;
681 } catch ( Exception e){
682 Log.e(TAG,"Failed to write serviceStateFile xml");
683 e.printStackTrace();
684 if (fos != null) {
685 mServiceStateFile.failWrite(fos);
686 }
687 return false;
688 }
689 }
690
691 public int updateServiceState(int userId , int uid,
692 Map<String , Boolean> serviceState) {
nxf500513a018e72019-04-23 17:11:41 +0530693 boolean success = false;
694 //HashMap<ComponentName ,NfcApduServiceInfo> nfcOffHostServiceMap = mRegisteredNfcServicesCache.getApduservicesMaps();
nxpandroida9a68ba2016-01-14 21:12:17 +0530695 if(NfcService.getInstance().getAidRoutingTableStatus() == 0x00) {
696 Log.e(TAG, " Aid Routing Table still availble , No need to disable services");
697 return 0xFF;
698 }
699 synchronized(mLock) {
700 Iterator<Map.Entry<String , Boolean>> it =
701 serviceState.entrySet().iterator();
702 while(it.hasNext()) {
703 Map.Entry<String , Boolean> entry =
704 (Map.Entry<String , Boolean>) it.next();
705 ComponentName componentName = ComponentName.unflattenFromString(entry.getKey());
nxf500513a018e72019-04-23 17:11:41 +0530706 NfcApduServiceInfo serviceInfo = getService(userId, componentName);
707 Log.e(TAG, "updateServiceState " + entry.getKey());
708 Log.e(TAG, "updateServiceState " + entry.getValue());
nxpandroida9a68ba2016-01-14 21:12:17 +0530709 if (serviceInfo != null) {
nxpandroid34627bd2016-05-27 15:52:30 +0530710 serviceInfo.enableService(CardEmulation.CATEGORY_OTHER, entry.getValue());
nxpandroida9a68ba2016-01-14 21:12:17 +0530711 } else {
712 Log.e(TAG, "Could not find service " + componentName);
713 return 0xFF;
714 }
715 }
nxpandroid34627bd2016-05-27 15:52:30 +0530716 Log.e(TAG,"2"+Thread.currentThread().getStackTrace()[2].getMethodName()+":WriteServiceStateToFile");
nxf500513a018e72019-04-23 17:11:41 +0530717 success = writeServiceStateToFile(userId);
nxpandroida9a68ba2016-01-14 21:12:17 +0530718 }
719 invalidateCache(ActivityManager.getCurrentUser());
nxf500513a018e72019-04-23 17:11:41 +0530720 return (success?0x00:0xFF);
721 }
722
723 public boolean setOffHostSecureElement(int userId, int uid, ComponentName componentName,
724 String offHostSE) {
725 ArrayList<NfcApduServiceInfo> newServices = null;
726 synchronized (mLock) {
727 UserServices services = findOrCreateUserLocked(userId);
728 // Check if we can find this service
729 NfcApduServiceInfo serviceInfo = getService(userId, componentName);
730 if (serviceInfo == null) {
731 Log.e(TAG, "Service " + componentName + " does not exist.");
732 return false;
733 }
734 if (serviceInfo.getUid() != uid) {
735 // This is probably a good indication something is wrong here.
736 // Either newer service installed with different uid (but then
737 // we should have known about it), or somebody calling us from
738 // a different uid.
739 Log.e(TAG, "UID mismatch.");
740 return false;
741 }
742 if (offHostSE == null || serviceInfo.isOnHost()) {
743 Log.e(TAG, "OffHostSE mismatch with Service type");
744 return false;
745 }
746
747 DynamicSettings dynSettings = services.dynamicSettings.get(componentName);
748 if (dynSettings == null) {
749 dynSettings = new DynamicSettings(uid);
750 }
751 dynSettings.offHostSE = offHostSE;
752 boolean success = writeDynamicSettingsLocked();
753 if (!success) {
754 Log.e(TAG, "Failed to persist AID group.");
755 dynSettings.offHostSE = null;
756 return false;
757 }
758
759 serviceInfo.setOffHostSecureElement(offHostSE);
760 newServices = new ArrayList<NfcApduServiceInfo>(services.services.values());
761 }
762 // Make callback without the lock held
763 mCallback.onServicesUpdated(userId, newServices);
764 return true;
765 }
766
767 public boolean unsetOffHostSecureElement(int userId, int uid, ComponentName componentName) {
768 ArrayList<NfcApduServiceInfo> newServices = null;
769 synchronized (mLock) {
770 UserServices services = findOrCreateUserLocked(userId);
771 // Check if we can find this service
772 NfcApduServiceInfo serviceInfo = getService(userId, componentName);
773 if (serviceInfo == null) {
774 Log.e(TAG, "Service " + componentName + " does not exist.");
775 return false;
776 }
777 if (serviceInfo.getUid() != uid) {
778 // This is probably a good indication something is wrong here.
779 // Either newer service installed with different uid (but then
780 // we should have known about it), or somebody calling us from
781 // a different uid.
782 Log.e(TAG, "UID mismatch.");
783 return false;
784 }
785 if (serviceInfo.isOnHost() || serviceInfo.getOffHostSecureElement() == null) {
786 Log.e(TAG, "OffHostSE is not set");
787 return false;
788 }
789 serviceInfo.unsetOffHostSecureElement();
790 DynamicSettings dynSettings = services.dynamicSettings.get(componentName);
791 if (dynSettings != null) {
792 String offHostSE = dynSettings.offHostSE;
793 dynSettings.offHostSE = serviceInfo.getOffHostSecureElement();
794 boolean success = writeDynamicSettingsLocked();
795 if (!success) {
796 Log.e(TAG, "Failed to persist AID group.");
797 dynSettings.offHostSE = offHostSE;
798 return false;
799 }
800 }
801
802 newServices = new ArrayList<NfcApduServiceInfo>(services.services.values());
803 }
804 // Make callback without the lock held
805 mCallback.onServicesUpdated(userId, newServices);
806 return true;
nxpandroida9a68ba2016-01-14 21:12:17 +0530807 }
808
nxpandroid64fd68c2015-09-23 16:45:15 +0530809 public boolean registerAidGroupForService(int userId, int uid,
nxf500513a018e72019-04-23 17:11:41 +0530810 ComponentName componentName, NfcAidGroup nfcAidGroup) {
811 ArrayList<NfcApduServiceInfo> newServices = null;
nxpandroid64fd68c2015-09-23 16:45:15 +0530812 boolean success;
813 synchronized (mLock) {
814 UserServices services = findOrCreateUserLocked(userId);
815 // Check if we can find this service
nxf500513a018e72019-04-23 17:11:41 +0530816 NfcApduServiceInfo serviceInfo = getService(userId, componentName);
nxpandroid64fd68c2015-09-23 16:45:15 +0530817 if (serviceInfo == null) {
818 Log.e(TAG, "Service " + componentName + " does not exist.");
819 return false;
820 }
821 if (serviceInfo.getUid() != uid) {
822 // This is probably a good indication something is wrong here.
823 // Either newer service installed with different uid (but then
824 // we should have known about it), or somebody calling us from
825 // a different uid.
826 Log.e(TAG, "UID mismatch.");
827 return false;
828 }
829 // Do another AID validation, since a caller could have thrown in a modified
nxf500513a018e72019-04-23 17:11:41 +0530830 // NfcAidGroup object with invalid AIDs over Binder.
831 List<String> aids = nfcAidGroup.getAids();
nxpandroid64fd68c2015-09-23 16:45:15 +0530832 for (String aid : aids) {
833 if (!CardEmulation.isValidAid(aid)) {
834 Log.e(TAG, "AID " + aid + " is not a valid AID");
835 return false;
836 }
837 }
nxf500513a018e72019-04-23 17:11:41 +0530838 serviceInfo.setOrReplaceDynamicNfcAidGroup(nfcAidGroup);
839 DynamicSettings dynSettings = services.dynamicSettings.get(componentName);
840 if (dynSettings == null) {
841 dynSettings = new DynamicSettings(uid);
842 dynSettings.offHostSE = serviceInfo.getOffHostSecureElement();
843 services.dynamicSettings.put(componentName, dynSettings);
nxpandroid64fd68c2015-09-23 16:45:15 +0530844 }
nxf500513a018e72019-04-23 17:11:41 +0530845 dynSettings.aidGroups.put(nfcAidGroup.getCategory(), nfcAidGroup);
846 success = writeDynamicSettingsLocked();
nxpandroid64fd68c2015-09-23 16:45:15 +0530847 if (success) {
nxf500513a018e72019-04-23 17:11:41 +0530848 newServices = new ArrayList<NfcApduServiceInfo>(services.services.values());
nxpandroid64fd68c2015-09-23 16:45:15 +0530849 } else {
850 Log.e(TAG, "Failed to persist AID group.");
851 // Undo registration
nxf500513a018e72019-04-23 17:11:41 +0530852 dynSettings.aidGroups.remove(nfcAidGroup.getCategory());
nxpandroid64fd68c2015-09-23 16:45:15 +0530853 }
854 }
855 if (success) {
856 // Make callback without the lock held
857 mCallback.onServicesUpdated(userId, newServices);
858 }
859 return success;
860 }
861
nxf500513a018e72019-04-23 17:11:41 +0530862 public NfcAidGroup getAidGroupForService(int userId, int uid, ComponentName componentName,
nxpandroid64fd68c2015-09-23 16:45:15 +0530863 String category) {
nxf500513a018e72019-04-23 17:11:41 +0530864 NfcApduServiceInfo serviceInfo = getService(userId, componentName);
nxpandroid64fd68c2015-09-23 16:45:15 +0530865 if (serviceInfo != null) {
866 if (serviceInfo.getUid() != uid) {
867 Log.e(TAG, "UID mismatch");
868 return null;
869 }
nxf500513a018e72019-04-23 17:11:41 +0530870 return serviceInfo.getDynamicNfcAidGroupForCategory(category);
nxpandroid64fd68c2015-09-23 16:45:15 +0530871 } else {
872 Log.e(TAG, "Could not find service " + componentName);
873 return null;
874 }
875 }
876
877 public boolean removeAidGroupForService(int userId, int uid, ComponentName componentName,
878 String category) {
879 boolean success = false;
nxf500513a018e72019-04-23 17:11:41 +0530880 ArrayList<NfcApduServiceInfo> newServices = null;
nxpandroid64fd68c2015-09-23 16:45:15 +0530881 synchronized (mLock) {
882 UserServices services = findOrCreateUserLocked(userId);
nxf500513a018e72019-04-23 17:11:41 +0530883 NfcApduServiceInfo serviceInfo = getService(userId, componentName);
nxpandroid64fd68c2015-09-23 16:45:15 +0530884 if (serviceInfo != null) {
885 if (serviceInfo.getUid() != uid) {
886 // Calling from different uid
887 Log.e(TAG, "UID mismatch");
888 return false;
889 }
nxf500513a018e72019-04-23 17:11:41 +0530890 if (!serviceInfo.removeDynamicNfcAidGroupForCategory(category)) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530891 Log.e(TAG," Could not find dynamic AIDs for category " + category);
892 return false;
893 }
894 // Remove from local cache
nxf500513a018e72019-04-23 17:11:41 +0530895 DynamicSettings dynAids = services.dynamicSettings.get(componentName);
nxpandroid64fd68c2015-09-23 16:45:15 +0530896 if (dynAids != null) {
nxf500513a018e72019-04-23 17:11:41 +0530897 NfcAidGroup deletedGroup = dynAids.aidGroups.remove(category);
898 success = writeDynamicSettingsLocked();
nxpandroid64fd68c2015-09-23 16:45:15 +0530899 if (success) {
nxf500513a018e72019-04-23 17:11:41 +0530900 newServices = new ArrayList<NfcApduServiceInfo>(services.services.values());
nxpandroid64fd68c2015-09-23 16:45:15 +0530901 } else {
902 Log.e(TAG, "Could not persist deleted AID group.");
903 dynAids.aidGroups.put(category, deletedGroup);
904 return false;
905 }
906 } else {
907 Log.e(TAG, "Could not find aid group in local cache.");
908 }
909 } else {
910 Log.e(TAG, "Service " + componentName + " does not exist.");
911 }
912 }
913 if (success) {
914 mCallback.onServicesUpdated(userId, newServices);
915 }
916 return success;
917 }
918
nxf500513a018e72019-04-23 17:11:41 +0530919 void initialize() {
920 synchronized (mLock) {
921 readDynamicSettingsLocked();
922 }
923 invalidateCache(ActivityManager.getCurrentUser());
924 }
925
nxpandroid64fd68c2015-09-23 16:45:15 +0530926 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
927 pw.println("Registered HCE services for current user: ");
928 UserServices userServices = findOrCreateUserLocked(ActivityManager.getCurrentUser());
nxf500513a018e72019-04-23 17:11:41 +0530929 for (NfcApduServiceInfo service : userServices.services.values()) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530930 service.dump(fd, pw, args);
931 pw.println("");
932 }
933 pw.println("");
934 }
nxpandroid64fd68c2015-09-23 16:45:15 +0530935}