blob: 5eb1e3bdff417ffc392ff9e3f40d903911589c6b [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 */
16
17/******************************************************************************
18 *
19 * The original Work has been changed by NXP Semiconductors.
20 *
nxf35421aca166a2018-02-06 16:00:50 +053021 * Copyright (C) 2015-2018 NXP Semiconductors
nxpandroid64fd68c2015-09-23 16:45:15 +053022 *
23 * Licensed under the Apache License, Version 2.0 (the "License");
24 * you may not use this file except in compliance with the License.
25 * You may obtain a copy of the License at
26 *
27 * http://www.apache.org/licenses/LICENSE-2.0
28 *
29 * Unless required by applicable law or agreed to in writing, software
30 * distributed under the License is distributed on an "AS IS" BASIS,
31 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32 * See the License for the specific language governing permissions and
33 * limitations under the License.
34 *
35 ******************************************************************************/
36package com.android.nfc.cardemulation;
37
Suryaprakash Kondurud7f25412018-04-12 12:24:24 +053038import android.app.ActivityManager;
39import android.app.ActivityManager.RunningTaskInfo;
40import android.app.ActivityThread;
41import android.content.Context;
nxpandroid64fd68c2015-09-23 16:45:15 +053042import android.util.Log;
43import android.util.SparseArray;
44
45import com.android.nfc.NfcService;
46
47import java.io.FileDescriptor;
48import java.io.PrintWriter;
49import java.util.Collections;
50import java.util.HashMap;
51import java.util.HashSet;
52import java.util.Hashtable;
53import java.util.Iterator;
54import java.util.List;
55import java.util.Map;
56import java.util.Set;
57import java.util.ArrayList;
58public class AidRoutingManager {
59 static final String TAG = "AidRoutingManager";
60
61 static final boolean DBG = true;
62
63 static final int ROUTE_HOST = 0x00;
64
65 // Every routing table entry is matched exact
66 static final int AID_MATCHING_EXACT_ONLY = 0x00;
67 // Every routing table entry can be matched either exact or prefix
68 static final int AID_MATCHING_EXACT_OR_PREFIX = 0x01;
69 // Every routing table entry is matched as a prefix
70 static final int AID_MATCHING_PREFIX_ONLY = 0x02;
nxpandroidcbf24822017-07-12 21:37:17 +053071 // Every routing table entry can be matched either exact or prefix or subset only
72 static final int AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX = 0x03;
nxpandroid64fd68c2015-09-23 16:45:15 +053073 //Behavior as per Android-L, supporting prefix match and full
74 //match for both OnHost and OffHost apps.
75 static final int AID_MATCHING_L = 0x01;
76 //Behavior as per Android-KitKat by NXP, supporting prefix match for
77 //OffHost and prefix and full both for OnHost apps.
78 static final int AID_MATCHING_K = 0x02;
79 // This is the default IsoDep protocol route; it means
80 // that for any AID that needs to be routed to this
81 // destination, we won't need to add a rule to the routing
82 // table, because this destination is already the default route.
83 //
84 // For Nexus devices, the default route is always 0x00.
85 int mDefaultRoute;
nxpandroid34627bd2016-05-27 15:52:30 +053086 boolean mRoutingTableChanged;
nxpandroid64fd68c2015-09-23 16:45:15 +053087 // For Nexus devices, just a static route to the eSE
88 // OEMs/Carriers could manually map off-host AIDs
89 // to the correct eSE/UICC based on state they keep.
nxf500510626e0e2019-02-08 14:57:00 +053090 int mDefaultOffHostRoute;
nxpandroid64fd68c2015-09-23 16:45:15 +053091
92 // How the NFC controller can match AIDs in the routing table;
93 // see AID_MATCHING constants
nxf500510626e0e2019-02-08 14:57:00 +053094 int mAidMatchingSupport;
95 int mAidMatchingPlatform;
nxpandroida9a68ba2016-01-14 21:12:17 +053096 //Changed from final to private int to update RoutingtableSize later in configureRouting.
97 private int mAidRoutingTableSize;
nxpandroid64fd68c2015-09-23 16:45:15 +053098 // Maximum AID routing table size
99 final Object mLock = new Object();
nxpandroid34627bd2016-05-27 15:52:30 +0530100 //set the status of last AID routes commit to routing table
101 //if true, last commit was successful,
102 //if false, there was an overflow of routing table for commit using last set of AID's in (mRouteForAid)
103 boolean mLastCommitStatus;
nxpandroid64fd68c2015-09-23 16:45:15 +0530104
105 // mAidRoutingTable contains the current routing table. The index is the route ID.
106 // The route can include routes to a eSE/UICC.
107 SparseArray<Set<String>> mAidRoutingTable =
108 new SparseArray<Set<String>>();
109
110 // Easy look-up what the route is for a certain AID
111 HashMap<String, Integer> mRouteForAid = new HashMap<String, Integer>();
112
113 // Easy look-up what the power state is for a certain AID
114 HashMap<String, Integer> mPowerForAid = new HashMap<String, Integer>();
115
116
117 private native int doGetDefaultRouteDestination();
118 private native int doGetDefaultOffHostRouteDestination();
119 private native int doGetAidMatchingMode();
120 private native int doGetAidMatchingPlatform();
121
122 final VzwRoutingCache mVzwRoutingCache;
123
Suryaprakash Kondurud7f25412018-04-12 12:24:24 +0530124 final ActivityManager mActivityManager;
125
nxpandroid64fd68c2015-09-23 16:45:15 +0530126 public AidRoutingManager() {
127 mDefaultRoute = doGetDefaultRouteDestination();
nxpandroid34627bd2016-05-27 15:52:30 +0530128 mRoutingTableChanged = false;
nxpandroid64fd68c2015-09-23 16:45:15 +0530129 if (DBG) Log.d(TAG, "mDefaultRoute=0x" + Integer.toHexString(mDefaultRoute));
130 mDefaultOffHostRoute = doGetDefaultOffHostRouteDestination();
131 if (DBG) Log.d(TAG, "mDefaultOffHostRoute=0x" + Integer.toHexString(mDefaultOffHostRoute));
132 mAidMatchingSupport = doGetAidMatchingMode();
133 if (DBG) Log.d(TAG, "mAidMatchingSupport=0x" + Integer.toHexString(mAidMatchingSupport));
134 mAidMatchingPlatform = doGetAidMatchingPlatform();
nxf500510626e0e2019-02-08 14:57:00 +0530135 if (DBG) Log.d(TAG, "mAidMatchingPlatform=0x" + Integer.toHexString(mAidMatchingPlatform));
nxpandroid64fd68c2015-09-23 16:45:15 +0530136 mVzwRoutingCache = new VzwRoutingCache();
nxpandroid34627bd2016-05-27 15:52:30 +0530137 mLastCommitStatus = true;
Suryaprakash Kondurud7f25412018-04-12 12:24:24 +0530138
139 Context context = (Context) ActivityThread.currentApplication();
140 mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
nxpandroid64fd68c2015-09-23 16:45:15 +0530141 }
142
143 public boolean supportsAidPrefixRouting() {
144 return mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX ||
nxpandroidcbf24822017-07-12 21:37:17 +0530145 mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY ||
146 mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX;
147 }
148
149 public boolean supportsAidSubsetRouting() {
150 return mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX;
nxpandroid64fd68c2015-09-23 16:45:15 +0530151 }
nxpandroid34627bd2016-05-27 15:52:30 +0530152
153 public boolean isRoutingTableUpdated() {
154 return mRoutingTableChanged;
155 }
nxpandroid64fd68c2015-09-23 16:45:15 +0530156 void clearNfcRoutingTableLocked() {
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530157 /*
Nikhil Chhabra27df0f72018-01-11 10:19:11 +0530158 for (Map.Entry<String, Integer> aidEntry : mRouteForAid.entrySet()) {
159 String aid = aidEntry.getKey();
160 if (aid.endsWith("*")) {
161 if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) {
162 Log.e(TAG, "Device does not support prefix AIDs but AID [" + aid
163 + "] is registered");
164 } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY) {
165 if (DBG) Log.d(TAG, "Unrouting prefix AID " + aid);
166 // Cut off '*' since controller anyway treats all AIDs as a prefix
167 aid = aid.substring(0, aid.length() - 1);
168 } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX ||
169 mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) {
170 aid = aid.substring(0, aid.length() - 1);
171 if (DBG) Log.d(TAG, "Unrouting prefix AID " + aid);
172 }
173 } else if (aid.endsWith("#")) {
174 if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) {
175 Log.e(TAG, "Device does not support subset AIDs but AID [" + aid
176 + "] is registered");
177 } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY ||
178 mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX) {
179 Log.e(TAG, "Device does not support subset AIDs but AID [" + aid
180 + "] is registered");
181 } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) {
182 if (DBG) Log.d(TAG, "Unrouting subset AID " + aid);
183 aid = aid.substring(0, aid.length() - 1);
184 }
185 } else {
186 if (DBG) Log.d(TAG, "Unrouting exact AID " + aid);
187 }
188 NfcService.getInstance().unrouteAids(aid);
189 }
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530190 */
nxpandroid64fd68c2015-09-23 16:45:15 +0530191 NfcService.getInstance().clearRouting();
192 mRouteForAid.clear();
nxpandroidcbf24822017-07-12 21:37:17 +0530193 mPowerForAid.clear();
nxpandroid64fd68c2015-09-23 16:45:15 +0530194 mAidRoutingTable.clear();
195 }
196
nxpandroida5fd6622017-07-31 16:15:18 +0530197 public boolean configureApduPatternRouting(List<ApduPatternResolveInfo> apduPatternList) {
198 if(apduPatternList.size() == 0x00 || apduPatternList == null)
199 return false;
200 NfcService.getInstance().unrouteApduPattern("FFFFFFFFFFFFFFEF");
201 for(ApduPatternResolveInfo apduPatternInfo : apduPatternList) {
202 NfcService.getInstance().routeApduPattern(apduPatternInfo.referenceData,apduPatternInfo.mask,
203 apduPatternInfo.route,apduPatternInfo.powerState);
204 }
205 return true;
206 }
207
nxf500510626e0e2019-02-08 14:57:00 +0530208 public void refreshConfigParameters() {
209 mDefaultRoute = doGetDefaultRouteDestination();
210 if (DBG)
211 Log.d(TAG, "mDefaultRoute=0x" + Integer.toHexString(mDefaultRoute));
212 mDefaultOffHostRoute = doGetDefaultOffHostRouteDestination();
213 if (DBG)
214 Log.d(TAG, "mDefaultOffHostRoute=0x" + Integer.toHexString(mDefaultOffHostRoute));
215 mAidMatchingSupport = doGetAidMatchingMode();
216 if (DBG)
217 Log.d(TAG, "mAidMatchingSupport=0x" + Integer.toHexString(mAidMatchingSupport));
218 mAidMatchingPlatform = doGetAidMatchingPlatform();
219 }
220
nxpandroid64fd68c2015-09-23 16:45:15 +0530221 public boolean configureRouting(HashMap<String, AidElement> aidMap) {
nxpandroid34627bd2016-05-27 15:52:30 +0530222 mRoutingTableChanged = false;
nxf500510626e0e2019-02-08 14:57:00 +0530223 //To handle Dynamic change in config files.
224 refreshConfigParameters();
nxpandroid64fd68c2015-09-23 16:45:15 +0530225 mDefaultRoute = NfcService.getInstance().GetDefaultRouteLoc();
226 boolean aidRouteResolved = false;
nxpandroida9a68ba2016-01-14 21:12:17 +0530227 if (DBG) Log.d(TAG, "mAidMatchingPlatform=0x" + Integer.toHexString(mAidMatchingPlatform));
228 mAidRoutingTableSize = NfcService.getInstance().getAidRoutingTableSize();
nxpandroid64fd68c2015-09-23 16:45:15 +0530229 if (DBG) Log.d(TAG, "mDefaultRoute=0x" + Integer.toHexString(mDefaultRoute));
230 Hashtable<String, AidElement> routeCache = new Hashtable<String, AidElement>(50);
231 SparseArray<Set<String>> aidRoutingTable = new SparseArray<Set<String>>(aidMap.size());
232 HashMap<String, Integer> routeForAid = new HashMap<String, Integer>(aidMap.size());
233 HashMap<String, Integer> powerForAid = new HashMap<String, Integer>(aidMap.size());
nxpandroidcbf24822017-07-12 21:37:17 +0530234 HashMap<String, Integer> infoForAid = new HashMap<String, Integer>(aidMap.size());
nxpandroid64fd68c2015-09-23 16:45:15 +0530235 // Then, populate internal data structures first
236 DefaultAidRouteResolveCache defaultRouteCache = new DefaultAidRouteResolveCache();
237
238 for (Map.Entry<String, AidElement> aidEntry : aidMap.entrySet()) {
239 AidElement elem = aidEntry.getValue();
240 int route = elem.getRouteLocation();
241 int power = elem.getPowerState();
nxpandroidcbf24822017-07-12 21:37:17 +0530242 int aidType = elem.getAidInfo();
nxpandroid64fd68c2015-09-23 16:45:15 +0530243 if (route == -1 ) {
244 route = mDefaultOffHostRoute;
245 elem.setRouteLocation(route);
246 }
247 String aid = aidEntry.getKey();
248 Set<String> entries = aidRoutingTable.get(route, new HashSet<String>());
249 entries.add(aid);
250 aidRoutingTable.put(route, entries);
251 routeForAid.put(aid, route);
252 powerForAid.put(aid, power);
nxpandroidcbf24822017-07-12 21:37:17 +0530253 infoForAid.put(aid, aidType);
nxpandroid64fd68c2015-09-23 16:45:15 +0530254 if (DBG) Log.d(TAG, "#######Routing AID " + aid + " to route "
255 + Integer.toString(route) + " with power "+ power);
256 }
257
258 synchronized (mLock) {
259 if (routeForAid.equals(mRouteForAid)) {
Suryaprakash Kondurud7f25412018-04-12 12:24:24 +0530260 if (DBG) Log.d(TAG, "Routing table unchanged");
nxpandroid34627bd2016-05-27 15:52:30 +0530261 if(mLastCommitStatus == false){
262 NfcService.getInstance().updateStatusOfServices(false);
263 NfcService.getInstance().notifyRoutingTableFull();
264 }
265 else
266 {/*If last commit status was success, And a new service is added whose AID's are
267 already resolved by previously installed services, service state of newly installed app needs to be updated*/
268 NfcService.getInstance().updateStatusOfServices(true);
269 }
Pratap Reddy8f473f02018-04-23 15:18:30 +0530270 if (isProcessingTapAgain() || NfcService.getInstance().mIsRoutingTableDirty) {
Suryaprakash Kondurud7f25412018-04-12 12:24:24 +0530271 if (DBG) Log.d(TAG, "Routing table unchanged, but commit the routing");
272 NfcService.getInstance().commitRouting();
273 } else {
274 if (DBG) Log.d(TAG, "Routing table unchanged, not updating");
275 }
nxpandroid64fd68c2015-09-23 16:45:15 +0530276 return false;
277 }
nxpandroidebf53fb2016-12-22 18:48:59 +0530278
nxpandroid64fd68c2015-09-23 16:45:15 +0530279 // Otherwise, update internal structures and commit new routing
280 clearNfcRoutingTableLocked();
281 mRouteForAid = routeForAid;
282 mPowerForAid = powerForAid;
283 mAidRoutingTable = aidRoutingTable;
284 for(int routeIndex=0; routeIndex < 0x03; routeIndex++) {
285 routeCache.clear();
286 if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY ||
287 mAidMatchingPlatform == AID_MATCHING_K) {
288 /* If a non-default route registers an exact AID which is shorter
289 * than this exact AID, this will create a problem with controllers
290 * that treat every AID in the routing table as a prefix.
291 * For example, if App A registers F0000000041010 as an exact AID,
292 * and App B registers F000000004 as an exact AID, and App B is not
293 * the default route, the following would be added to the routing table:
294 * F000000004 -> non-default destination
295 * However, because in this mode, the controller treats every routing table
296 * entry as a prefix, it means F0000000041010 would suddenly go to the non-default
297 * destination too, whereas it should have gone to the default.
298 *
299 * The only way to prevent this is to add the longer AIDs of the
300 * default route at the top of the table, so they will be matched first.
301 */
302 Set<String> defaultRouteAids = mAidRoutingTable.get(mDefaultRoute);
nxf382934d174fd2018-06-29 13:02:43 +0530303 if (defaultRouteAids != null) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530304 for (String defaultRouteAid : defaultRouteAids) {
305 // Check whether there are any shorted AIDs routed to non-default
306 // TODO this is O(N^2) run-time complexity...
307 for (Map.Entry<String, Integer> aidEntry : mRouteForAid.entrySet()) {
308 String aid = aidEntry.getKey();
309 int route = aidEntry.getValue();
310 if (defaultRouteAid.startsWith(aid) && route != mDefaultRoute) {
311 if (DBG) Log.d(TAG, "Adding AID " + defaultRouteAid + " for default " +
312 "route, because a conflicting shorter AID will be added" +
313 "to the routing table");
314 AidElement elem = aidMap.get(defaultRouteAid);
315 elem.setRouteLocation(mDefaultRoute);
316 routeCache.put(defaultRouteAid, elem);
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530317 //NfcService.getInstance().routeAids(defaultRouteAid, mDefaultRoute, mPowerForAid.get(defaultRouteAid),infoForAid.get(defaultRouteAid));
nxpandroid64fd68c2015-09-23 16:45:15 +0530318 }
319 }
320 }
321 }
322 }
323
Suhas Sureshce6a3442018-07-30 21:06:36 +0530324 // Add AID entries for all non-default routes
nxpandroid64fd68c2015-09-23 16:45:15 +0530325 for (int i = 0; i < mAidRoutingTable.size(); i++) {
326 int route = mAidRoutingTable.keyAt(i);
Suhas Sureshce6a3442018-07-30 21:06:36 +0530327 if (route != mDefaultRoute) {
328 Set<String> aidsForRoute = mAidRoutingTable.get(route);
329 for (String aid : aidsForRoute) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530330 if (aid.endsWith("*")) {
331 if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) {
332 Log.e(TAG, "This device does not support prefix AIDs.");
333 } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY) {
334 if (DBG) Log.d(TAG, "Routing prefix AID " + aid + " to route "
335 + Integer.toString(route));
336 // Cut off '*' since controller anyway treats all AIDs as a prefix
337 AidElement elem = aidMap.get(aid);
338 elem.setAid(aid.substring(0,aid.length() - 1));
339 routeCache.put(aid, elem);
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530340 //NfcService.getInstance().routeAids(aid.substring(0,
341 //aid.length() - 1), route, mPowerForAid.get(aid),infoForAid.get(aid));
nxpandroidcbf24822017-07-12 21:37:17 +0530342 } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX
343 || mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) {
nxpandroid64fd68c2015-09-23 16:45:15 +0530344 Log.d(TAG, "Routing AID in AID_MATCHING_EXACT_OR_PREFIX");
345 if (DBG) Log.d(TAG, "Routing prefix AID " + aid + " to route "
346 + Integer.toString(route));
347 AidElement elem = aidMap.get(aid);
348 routeCache.put(aid, elem);
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530349 //NfcService.getInstance().routeAids(aid, route, (mPowerForAid.get(aid)),infoForAid.get(aid));
nxpandroidcbf24822017-07-12 21:37:17 +0530350 }
351 } else if (aid.endsWith("#")) {
352 if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) {
353 Log.e(TAG, "Device does not support subset AIDs but AID [" + aid
354 + "] is registered");
355 } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY ||
356 mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX) {
357 Log.e(TAG, "Device does not support subset AIDs but AID [" + aid
358 + "] is registered");
359 } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) {
360 if (DBG) Log.d(TAG, "Routing subset AID " + aid + " to route "
361 + Integer.toString(route));
362 AidElement elem = aidMap.get(aid);
363 routeCache.put(aid, elem);
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530364 //NfcService.getInstance().routeAids(aid, route, (mPowerForAid.get(aid)),infoForAid.get(aid));
nxpandroid64fd68c2015-09-23 16:45:15 +0530365 }
366 } else {
367 if (DBG) Log.d(TAG, "Routing exact AID " + aid + " to route "
368 + Integer.toString(route));
369 AidElement elem = aidMap.get(aid);
370 routeCache.put(aid, elem);
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530371 //NfcService.getInstance().routeAids(aid, route, mPowerForAid.get(aid),infoForAid.get(aid));
nxpandroid64fd68c2015-09-23 16:45:15 +0530372 }
373 }
374 }
375 }
376
377 if((routeIndex == 0x00) && (defaultRouteCache.calculateAidRouteSize(routeCache) <= mAidRoutingTableSize)) {
378 // maximum aid table size is less than AID route table size
379 aidRouteResolved = true;
380 break;
381 } else {
382 defaultRouteCache.updateDefaultAidRouteCache(routeCache , mDefaultRoute);
383 mDefaultRoute = defaultRouteCache.getNextRouteLoc();
384 if(mDefaultRoute == 0xFF)
385 {
386 break;
387 }
388 }
389
390 }
391 }
392 if(aidRouteResolved == false) {
393 if(mAidRoutingTable.size() == 0x00) {
394 aidRouteResolved = true;
395 //update the cache , no applications present.
396 }
397 else if(defaultRouteCache.resolveDefaultAidRoute() == true) {
398 aidRouteResolved = true;
399 routeCache = defaultRouteCache.getResolvedAidRouteCache();
400 //update preferences if different
401 NfcService.getInstance().setDefaultAidRouteLoc(defaultRouteCache.getResolvedAidRoute());
402 } else {
403 NfcService.getInstance().notifyRoutingTableFull();
404 }
405 }
nxpandroid34627bd2016-05-27 15:52:30 +0530406 // And finally commit the routing and update the status of commit for each service
nxpandroid64fd68c2015-09-23 16:45:15 +0530407 if(aidRouteResolved == true) {
Sachin Dhivareef9b3f22018-06-08 13:10:20 +0530408 mRoutingTableChanged = true;
nxpandroid64fd68c2015-09-23 16:45:15 +0530409 commit(routeCache);
nxpandroid34627bd2016-05-27 15:52:30 +0530410 NfcService.getInstance().updateStatusOfServices(true);
411 mLastCommitStatus = true;
412 }
413 else{
414 NfcService.getInstance().updateStatusOfServices(false);
415 mLastCommitStatus = false;
nxpandroid64fd68c2015-09-23 16:45:15 +0530416 }
417// NfcService.getInstance().commitRouting();
418
419 return true;
420 }
421
422 private void commit(Hashtable<String, AidElement> routeCache ) {
423
424 if(routeCache != null) {
425 List<AidElement> list = Collections.list(routeCache.elements());
426 Collections.sort(list);
427 Iterator<AidElement> it = list.iterator();
428 NfcService.getInstance().clearRouting();
429 while(it.hasNext()){
430 AidElement element =it.next();
431 if (DBG) Log.d (TAG, element.toString());
432 NfcService.getInstance().routeAids(
433 element.getAid(),
434 element.getRouteLocation(),
nxpandroidcbf24822017-07-12 21:37:17 +0530435 element.getPowerState(),
436 element.getAidInfo());
nxpandroid64fd68c2015-09-23 16:45:15 +0530437 }
438 }
439 // And finally commit the routing
440 NfcService.getInstance().commitRouting();
441 }
442
443 /**
444 * This notifies that the AID routing table in the controller
445 * has been cleared (usually due to NFC being turned off).
446 */
447 public void onNfccRoutingTableCleared() {
448 // The routing table in the controller was cleared
449 // To stay in sync, clear our own tables.
450 synchronized (mLock) {
451 mAidRoutingTable.clear();
452 mRouteForAid.clear();
453 }
454 }
455
456 public boolean UpdateVzwCache(byte[] aid,int route,int power,boolean isAllowed){
457 mVzwRoutingCache.addAid(aid,route,power,isAllowed);
458 return true;
459 }
460
461 public VzwRoutingCache GetVzwCache(){
462 return mVzwRoutingCache;
463 }
464
465 public void ClearVzwCache() {
466 mVzwRoutingCache.clear();
467 }
468
469 public int getAidMatchMode() {
470 return mAidMatchingSupport;
471 }
472
nxpandroidebf53fb2016-12-22 18:48:59 +0530473 public boolean getLastCommitRoutingStatus() {
474 return mLastCommitStatus;
475 }
476
nxpandroid64fd68c2015-09-23 16:45:15 +0530477 public int getAidMatchingPlatform() {
478 return mAidMatchingPlatform;
479 }
480
481 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
482 pw.println("Routing table:");
nxpandroid281eb922016-08-25 20:27:46 +0530483 pw.println(" Default route: " +
484 (NfcService.getInstance().GetDefaultRouteLoc() == 0x00 ? "host" : "secure element"));
nxpandroid64fd68c2015-09-23 16:45:15 +0530485 synchronized (mLock) {
486 for (int i = 0; i < mAidRoutingTable.size(); i++) {
487 Set<String> aids = mAidRoutingTable.valueAt(i);
488 pw.println(" Routed to 0x" + Integer.toHexString(mAidRoutingTable.keyAt(i)) + ":");
489 for (String aid : aids) {
490 pw.println(" \"" + aid + "\"");
491 }
492 }
493 }
494 }
nxpandroida5fd6622017-07-31 16:15:18 +0530495
496 final class ApduPatternResolveInfo {
497 public String mask;
498 public String referenceData;
499 public int route;
500 public int powerState;
501 }
502
nxpandroid64fd68c2015-09-23 16:45:15 +0530503 final class DefaultAidRouteResolveCache {
504 static final int AID_HDR_LENGTH = 0x04; // TAG + ROUTE + LENGTH_BYTE + POWER
505 static final int MAX_AID_ENTRIES = 50;
506 //AidCacheTable contains the current aid routing table for particular route.
507 //The index is the route ID.
508 private SparseArray<Hashtable<String, AidElement>> aidCacheTable;
509 private HashMap <Integer , Integer> aidCacheSize;
510 //HashMap containing aid routing size .
511 //The index is route ID.
512 private Hashtable<String, AidElement> resolvedAidCache;//HashTable containing resolved default aid routeCache
513 private int mCurrDefaultAidRoute; // current default route in preferences
514 private int mResolvedAidRoute; //resolved aid route location
515 private boolean mAidRouteResolvedStatus; // boolean value
516 private ArrayList<Integer> aidRoutes;//non-default route location
517
518 DefaultAidRouteResolveCache () {
519 aidCacheTable = new SparseArray<Hashtable<String, AidElement>>(0x03);
520 resolvedAidCache = new Hashtable<String, AidElement>();
521 aidCacheSize= new HashMap <Integer , Integer>(0x03);
522 aidRoutes = new ArrayList<Integer>();
523 mCurrDefaultAidRoute = NfcService.getInstance().GetDefaultRouteLoc();
524 mAidRouteResolvedStatus = false;
525 }
526
527 private Hashtable<String, AidElement> extractResolvedCache()
528 {
529 if(mAidRouteResolvedStatus == false) {
530 return null;
531 }
532 for(int i=0;i< aidCacheTable.size() ;i++) {
533 int route = aidCacheTable.keyAt(i);
534 if(route == mResolvedAidRoute) {
535 return aidCacheTable.get(route);
536 }
537 }
538 return null;
539 }
540
541
542 public int calculateAidRouteSize(Hashtable<String, AidElement> routeCache) {
543 int routeTableSize = 0x00;
544 int routeAidCount = 0x00;
545 for(Map.Entry<String, AidElement> aidEntry : routeCache.entrySet()) {
546 String aid = aidEntry.getKey();
547 if(aid.endsWith("*")) {
548 routeTableSize += ((aid.length() - 0x01) / 0x02) + AID_HDR_LENGTH; // removing prefix length
549 } else {
550 routeTableSize += (aid.length() / 0x02)+ AID_HDR_LENGTH;
551 }
552 routeAidCount++;
553 }
554 Log.d(TAG, "calculateAidRouteSize final Routing table size" +routeTableSize);
555 if(routeTableSize <= mAidRoutingTableSize && routeAidCount > MAX_AID_ENTRIES) {
556 routeTableSize = mAidRoutingTableSize + 0x01;
557 }
558 return routeTableSize;
559 }
560
561 public int updateDefaultAidRouteCache(Hashtable<String, AidElement> routeCache , int route) {
562 int routesize = 0x00;
563 Hashtable<String, AidElement> tempRouteCache = new Hashtable<String, AidElement>(0x50);
564 tempRouteCache.putAll(routeCache);
565 routesize = calculateAidRouteSize(tempRouteCache);
566 aidCacheTable.put(route, tempRouteCache);
567 aidCacheSize.put(route, routesize);
568 Log.d(TAG, "updateDefaultAidRouteCache Routing table size" +routesize);
569 return routesize;
570 }
571
572 public boolean resolveDefaultAidRoute () {
573
574 int minRoute = 0xFF;
575 int minAidRouteSize = mAidRoutingTableSize;
576 int tempRoute = 0x00;
577 int tempCacheSize = 0x00;
578 Hashtable<String, AidElement> aidRouteCache = new Hashtable<String, AidElement>();
579 Set<Integer> keys = aidCacheSize.keySet();
580 for (Integer key : keys) {
581 tempRoute = key;
582 tempCacheSize = aidCacheSize.get(key);
583 if (tempCacheSize <= minAidRouteSize) {
584 minAidRouteSize = tempCacheSize;
585 minRoute = tempRoute;
586 }
587 }
588 if(minRoute != 0xFF) {
589 mAidRouteResolvedStatus = true;
590 mResolvedAidRoute = minRoute;
591 Log.d(TAG, "min route found "+mResolvedAidRoute);
592 }
593
594 return mAidRouteResolvedStatus;
595 }
596
597 public int getResolvedAidRoute () {
598 return mResolvedAidRoute;
599 }
600
601 public Hashtable<String, AidElement> getResolvedAidRouteCache() {
602
603 return extractResolvedCache();
604 }
605
606 public int getNextRouteLoc() {
607
608 for (int i = 0; i < 0x03; i++) {
609 if((i != mCurrDefaultAidRoute) && (!aidRoutes.contains(i)))
610 {
611 aidRoutes.add(i);
612 return i;
613 }
614 }
615 return 0xFF;
616 }
617
618 }
Suryaprakash Kondurud7f25412018-04-12 12:24:24 +0530619
620 // Returns true if AppChooserActivity is foreground to restart RF discovery so that
621 // TapAgainDialog is dismissed when an external reader detects the device.
622 private boolean isProcessingTapAgain() {
623 String appChooserActivityClassName = AppChooserActivity.class.getName();
624 return appChooserActivityClassName.equals(getTopClass());
625 }
626
627 private String getTopClass() {
628 String topClass = null;
629 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
630 if (tasks != null && tasks.size() > 0) {
631 topClass = tasks.get(0).topActivity.getClassName();
632 }
633 return topClass;
634 }
nxpandroid64fd68c2015-09-23 16:45:15 +0530635}