nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 1 | /* |
| 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 | */ |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 16 | /****************************************************************************** |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 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 | ******************************************************************************/ |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 35 | package com.android.nfc.cardemulation; |
| 36 | |
| 37 | import android.util.Log; |
| 38 | import android.util.SparseArray; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 39 | import android.content.Context; |
| 40 | import android.app.ActivityThread; |
| 41 | import android.app.ActivityManager; |
| 42 | import android.app.ActivityManager.RunningTaskInfo; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 43 | import com.android.nfc.NfcService; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 44 | import android.util.SparseArray; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 45 | import java.io.FileDescriptor; |
| 46 | import java.io.PrintWriter; |
| 47 | import java.util.Collections; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 48 | import java.util.Arrays; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 49 | import java.util.HashMap; |
| 50 | import java.util.HashSet; |
| 51 | import java.util.Hashtable; |
| 52 | import java.util.Iterator; |
| 53 | import java.util.List; |
| 54 | import java.util.Map; |
| 55 | import java.util.Set; |
Ganesh Deva | c90b32d | 2019-07-12 11:53:10 +0530 | [diff] [blame] | 56 | import android.util.StatsLog; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 57 | import java.util.List; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 58 | import java.util.ArrayList; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 59 | import java.util.Hashtable; |
| 60 | import android.os.SystemProperties; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 61 | public class AidRoutingManager { |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 62 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 63 | static final String TAG = "AidRoutingManager"; |
| 64 | |
nxf50051 | 4ff9f42 | 2019-03-20 16:28:16 +0530 | [diff] [blame] | 65 | static final boolean DBG = |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 66 | ((SystemProperties.get("persist.nfc.ce_debug").equals("1")) ? true : false); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 67 | |
| 68 | static final int ROUTE_HOST = 0x00; |
| 69 | |
| 70 | // Every routing table entry is matched exact |
| 71 | static final int AID_MATCHING_EXACT_ONLY = 0x00; |
| 72 | // Every routing table entry can be matched either exact or prefix |
| 73 | static final int AID_MATCHING_EXACT_OR_PREFIX = 0x01; |
| 74 | // Every routing table entry is matched as a prefix |
| 75 | static final int AID_MATCHING_PREFIX_ONLY = 0x02; |
nxpandroid | cbf2482 | 2017-07-12 21:37:17 +0530 | [diff] [blame] | 76 | // Every routing table entry can be matched either exact or prefix or subset only |
| 77 | static final int AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX = 0x03; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 78 | |
| 79 | int mDefaultIsoDepRoute; |
| 80 | //Let mDefaultRoute as default aid route |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 81 | int mDefaultRoute; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 82 | |
| 83 | int mMaxAidRoutingTableSize; |
| 84 | int mDefaultAidRoute; |
| 85 | final byte[] mOffHostRouteUicc; |
| 86 | final byte[] mOffHostRouteEse; |
| 87 | // Used for backward compatibility in case application doesn't specify the |
| 88 | // SE |
| 89 | final int mDefaultOffHostRoute; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 90 | |
| 91 | // How the NFC controller can match AIDs in the routing table; |
| 92 | // see AID_MATCHING constants |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 93 | final int mAidMatchingSupport; |
nxpandroid | a9a68ba | 2016-01-14 21:12:17 +0530 | [diff] [blame] | 94 | private int mAidRoutingTableSize; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 95 | // Maximum AID routing table size |
| 96 | final Object mLock = new Object(); |
nxpandroid | 34627bd | 2016-05-27 15:52:30 +0530 | [diff] [blame] | 97 | //set the status of last AID routes commit to routing table |
| 98 | //if true, last commit was successful, |
| 99 | //if false, there was an overflow of routing table for commit using last set of AID's in (mRouteForAid) |
| 100 | boolean mLastCommitStatus; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 101 | |
| 102 | // mAidRoutingTable contains the current routing table. The index is the route ID. |
| 103 | // The route can include routes to a eSE/UICC. |
| 104 | SparseArray<Set<String>> mAidRoutingTable = |
| 105 | new SparseArray<Set<String>>(); |
| 106 | |
| 107 | // Easy look-up what the route is for a certain AID |
| 108 | HashMap<String, Integer> mRouteForAid = new HashMap<String, Integer>(); |
| 109 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 110 | private native int doGetDefaultRouteDestination(); |
| 111 | private native int doGetDefaultOffHostRouteDestination(); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 112 | private native byte[] doGetOffHostUiccDestination(); |
| 113 | private native byte[] doGetOffHostEseDestination(); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 114 | private native int doGetAidMatchingMode(); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 115 | private native int doGetDefaultIsoDepRouteDestination(); |
Suryaprakash Konduru | d7f2541 | 2018-04-12 12:24:24 +0530 | [diff] [blame] | 116 | final ActivityManager mActivityManager; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 117 | final class AidEntry { |
| 118 | boolean isOnHost; |
| 119 | String offHostSE; |
| 120 | int aidInfo; |
| 121 | int powerstate; |
| 122 | int route; |
| 123 | } |
Suryaprakash Konduru | d7f2541 | 2018-04-12 12:24:24 +0530 | [diff] [blame] | 124 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 125 | public AidRoutingManager() { |
| 126 | mDefaultRoute = doGetDefaultRouteDestination(); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 127 | if (DBG) |
| 128 | Log.d(TAG, "mDefaultRoute=0x" + Integer.toHexString(mDefaultRoute)); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 129 | mDefaultOffHostRoute = doGetDefaultOffHostRouteDestination(); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 130 | if (DBG) |
| 131 | Log.d(TAG, "mDefaultOffHostRoute=0x" + Integer.toHexString(mDefaultOffHostRoute)); |
| 132 | mOffHostRouteUicc = doGetOffHostUiccDestination(); |
| 133 | if (DBG) |
| 134 | Log.d(TAG, "mOffHostRouteUicc=" + Arrays.toString(mOffHostRouteUicc)); |
| 135 | mOffHostRouteEse = doGetOffHostEseDestination(); |
| 136 | if (DBG) |
| 137 | Log.d(TAG, "mOffHostRouteEse=" + Arrays.toString(mOffHostRouteEse)); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 138 | mAidMatchingSupport = doGetAidMatchingMode(); |
| 139 | if (DBG) Log.d(TAG, "mAidMatchingSupport=0x" + Integer.toHexString(mAidMatchingSupport)); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 140 | mDefaultAidRoute = NfcService.getInstance().GetDefaultRouteEntry() >> 0x08; |
| 141 | if (DBG) |
| 142 | Log.d(TAG, "mDefaultAidRoute=0x" + Integer.toHexString(mDefaultAidRoute)); |
| 143 | mDefaultIsoDepRoute = doGetDefaultIsoDepRouteDestination(); |
| 144 | if (DBG) Log.d(TAG, "mDefaultIsoDepRoute=0x" + Integer.toHexString(mDefaultIsoDepRoute)); |
nxpandroid | 34627bd | 2016-05-27 15:52:30 +0530 | [diff] [blame] | 145 | mLastCommitStatus = true; |
Suryaprakash Konduru | d7f2541 | 2018-04-12 12:24:24 +0530 | [diff] [blame] | 146 | |
| 147 | Context context = (Context) ActivityThread.currentApplication(); |
| 148 | mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | public boolean supportsAidPrefixRouting() { |
| 152 | return mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX || |
nxpandroid | cbf2482 | 2017-07-12 21:37:17 +0530 | [diff] [blame] | 153 | mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY || |
| 154 | mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX; |
| 155 | } |
| 156 | |
| 157 | public boolean supportsAidSubsetRouting() { |
| 158 | return mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 159 | } |
nxpandroid | 34627bd | 2016-05-27 15:52:30 +0530 | [diff] [blame] | 160 | |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 161 | public int calculateAidRouteSize(HashMap<String, AidEntry> routeCache) { |
| 162 | // TAG + ROUTE + LENGTH_BYTE + POWER |
| 163 | int AID_HDR_LENGTH = 0x04; |
| 164 | int routeTableSize = 0x00; |
| 165 | for(Map.Entry<String, AidEntry> aidEntry : routeCache.entrySet()) { |
| 166 | String aid = aidEntry.getKey(); |
| 167 | // removing prefix length |
| 168 | if(aid.endsWith("*")) { |
| 169 | routeTableSize += ((aid.length() - 0x01) / 0x02) + AID_HDR_LENGTH; |
| 170 | } else { |
| 171 | routeTableSize += (aid.length() / 0x02)+ AID_HDR_LENGTH; |
| 172 | } |
| 173 | } |
| 174 | if (DBG) Log.d(TAG, "calculateAidRouteSize: " + routeTableSize); |
| 175 | return routeTableSize; |
nxpandroid | 34627bd | 2016-05-27 15:52:30 +0530 | [diff] [blame] | 176 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 177 | |
| 178 | private void clearNfcRoutingTableLocked() { |
Nikhil Chhabra | 27df0f7 | 2018-01-11 10:19:11 +0530 | [diff] [blame] | 179 | for (Map.Entry<String, Integer> aidEntry : mRouteForAid.entrySet()) { |
| 180 | String aid = aidEntry.getKey(); |
| 181 | if (aid.endsWith("*")) { |
| 182 | if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) { |
| 183 | Log.e(TAG, "Device does not support prefix AIDs but AID [" + aid |
| 184 | + "] is registered"); |
| 185 | } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY) { |
| 186 | if (DBG) Log.d(TAG, "Unrouting prefix AID " + aid); |
| 187 | // Cut off '*' since controller anyway treats all AIDs as a prefix |
| 188 | aid = aid.substring(0, aid.length() - 1); |
| 189 | } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX || |
| 190 | mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) { |
| 191 | aid = aid.substring(0, aid.length() - 1); |
| 192 | if (DBG) Log.d(TAG, "Unrouting prefix AID " + aid); |
| 193 | } |
| 194 | } else if (aid.endsWith("#")) { |
| 195 | if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) { |
| 196 | Log.e(TAG, "Device does not support subset AIDs but AID [" + aid |
| 197 | + "] is registered"); |
| 198 | } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY || |
| 199 | mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX) { |
| 200 | Log.e(TAG, "Device does not support subset AIDs but AID [" + aid |
| 201 | + "] is registered"); |
| 202 | } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) { |
| 203 | if (DBG) Log.d(TAG, "Unrouting subset AID " + aid); |
| 204 | aid = aid.substring(0, aid.length() - 1); |
| 205 | } |
| 206 | } else { |
| 207 | if (DBG) Log.d(TAG, "Unrouting exact AID " + aid); |
| 208 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 209 | |
Nikhil Chhabra | 27df0f7 | 2018-01-11 10:19:11 +0530 | [diff] [blame] | 210 | NfcService.getInstance().unrouteAids(aid); |
| 211 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 212 | if (NfcService.getInstance().getNciVersion() != NfcService.getInstance().NCI_VERSION_1_0) { |
| 213 | // unRoute EmptyAid |
| 214 | NfcService.getInstance().unrouteAids(""); |
| 215 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 216 | } |
| 217 | |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 218 | private int getRouteForSecureElement(String se) { |
| 219 | if (se == null || se.length() <= 3) { |
| 220 | return 0; |
| 221 | } |
| 222 | try { |
| 223 | if (se.startsWith("eSE") && mOffHostRouteEse != null) { |
| 224 | int index = Integer.parseInt(se.substring(3)); |
| 225 | if (mOffHostRouteEse.length >= index && index > 0) { |
| 226 | return mOffHostRouteEse[index - 1] & 0xFF; |
| 227 | } |
| 228 | } else if (se.startsWith("SIM") && mOffHostRouteUicc != null) { |
| 229 | int index = Integer.parseInt(se.substring(3)); |
| 230 | if (mOffHostRouteUicc.length >= index && index > 0) { |
| 231 | return mOffHostRouteUicc[index - 1] & 0xFF; |
| 232 | } |
Ganesh Deva | 1ad7d6f | 2019-06-17 11:46:02 +0530 | [diff] [blame] | 233 | if (mOffHostRouteEse == null && mOffHostRouteUicc == null) |
| 234 | return mDefaultOffHostRoute; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 235 | } |
| 236 | } catch (NumberFormatException e) { |
| 237 | } |
| 238 | return 0; |
nxf50051 | 0626e0e | 2019-02-08 14:57:00 +0530 | [diff] [blame] | 239 | } |
| 240 | |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 241 | public boolean configureRouting(HashMap<String, AidEntry> aidMap, boolean force) { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 242 | boolean aidRouteResolved = false; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 243 | HashMap<String, AidEntry> aidRoutingTableCache = new HashMap<String, AidEntry>(aidMap.size()); |
| 244 | ArrayList<Integer> seList = new ArrayList<Integer>(); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 245 | SparseArray<Set<String>> aidRoutingTable = new SparseArray<Set<String>>(aidMap.size()); |
| 246 | HashMap<String, Integer> routeForAid = new HashMap<String, Integer>(aidMap.size()); |
nxpandroid | cbf2482 | 2017-07-12 21:37:17 +0530 | [diff] [blame] | 247 | HashMap<String, Integer> infoForAid = new HashMap<String, Integer>(aidMap.size()); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 248 | HashMap<String, Integer> powerForAid = new HashMap<String, Integer>(aidMap.size()); |
| 249 | mDefaultRoute = NfcService.getInstance().GetDefaultRouteLoc(); |
| 250 | mAidRoutingTableSize = NfcService.getInstance().getAidRoutingTableSize(); |
| 251 | mDefaultAidRoute = NfcService.getInstance().GetDefaultRouteEntry() >> 0x08; |
| 252 | Log.e(TAG, "Size of routing table"+mAidRoutingTableSize); |
| 253 | seList.add(mDefaultAidRoute); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 254 | // Then, populate internal data structures first |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 255 | for (Map.Entry<String, AidEntry> aidEntry : aidMap.entrySet()) { |
| 256 | int route = ROUTE_HOST; |
| 257 | if (!aidEntry.getValue().isOnHost) { |
| 258 | String offHostSE = aidEntry.getValue().offHostSE; |
| 259 | if (offHostSE == null) { |
| 260 | route = mDefaultOffHostRoute; |
| 261 | } else { |
| 262 | route = getRouteForSecureElement(offHostSE); |
| 263 | if (route == 0) { |
| 264 | Log.e(TAG, "Invalid Off host Aid Entry " + offHostSE); |
| 265 | continue; |
| 266 | } |
| 267 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 268 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 269 | if (!seList.contains(route)) |
| 270 | seList.add(route); |
| 271 | aidEntry.getValue().route = route; |
| 272 | int aidType = aidEntry.getValue().aidInfo; |
| 273 | int power = aidEntry.getValue().powerstate; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 274 | String aid = aidEntry.getKey(); |
| 275 | Set<String> entries = aidRoutingTable.get(route, new HashSet<String>()); |
| 276 | entries.add(aid); |
| 277 | aidRoutingTable.put(route, entries); |
| 278 | routeForAid.put(aid, route); |
nxpandroid | cbf2482 | 2017-07-12 21:37:17 +0530 | [diff] [blame] | 279 | infoForAid.put(aid, aidType); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 280 | powerForAid.put(aid, power); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 281 | if (DBG) Log.d(TAG, "#######Routing AID " + aid + " to route " |
| 282 | + Integer.toString(route) + " with power "+ power); |
| 283 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 284 | if (!seList.contains(ROUTE_HOST)) |
| 285 | seList.add(ROUTE_HOST); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 286 | |
| 287 | synchronized (mLock) { |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 288 | if (routeForAid.equals(mRouteForAid) && !force) { |
Suhas Suresh | ac4f88e | 2019-06-14 18:08:16 +0530 | [diff] [blame] | 289 | if (DBG) Log.d(TAG, "Routing table unchanged, not updating"); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 290 | return false; |
| 291 | } |
nxpandroid | ebf53fb | 2016-12-22 18:48:59 +0530 | [diff] [blame] | 292 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 293 | // Otherwise, update internal structures and commit new routing |
| 294 | clearNfcRoutingTableLocked(); |
| 295 | mRouteForAid = routeForAid; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 296 | mAidRoutingTable = aidRoutingTable; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 297 | mMaxAidRoutingTableSize = NfcService.getInstance().getAidRoutingTableSize(); |
| 298 | if (DBG) Log.d(TAG, "mMaxAidRoutingTableSize: " + mMaxAidRoutingTableSize); |
| 299 | |
| 300 | for(int index=0; index < seList.size(); index++) { |
| 301 | mDefaultRoute = seList.get(index); |
| 302 | if(index != 0) |
| 303 | if (DBG) Log.d(TAG, "AidRoutingTable is full, try to switch mDefaultRoute to 0x" + Integer.toHexString(mDefaultRoute)); |
| 304 | |
| 305 | aidRoutingTableCache.clear(); |
| 306 | if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY) { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 307 | /* If a non-default route registers an exact AID which is shorter |
| 308 | * than this exact AID, this will create a problem with controllers |
| 309 | * that treat every AID in the routing table as a prefix. |
| 310 | * For example, if App A registers F0000000041010 as an exact AID, |
| 311 | * and App B registers F000000004 as an exact AID, and App B is not |
| 312 | * the default route, the following would be added to the routing table: |
| 313 | * F000000004 -> non-default destination |
| 314 | * However, because in this mode, the controller treats every routing table |
| 315 | * entry as a prefix, it means F0000000041010 would suddenly go to the non-default |
| 316 | * destination too, whereas it should have gone to the default. |
| 317 | * |
| 318 | * The only way to prevent this is to add the longer AIDs of the |
| 319 | * default route at the top of the table, so they will be matched first. |
| 320 | */ |
| 321 | Set<String> defaultRouteAids = mAidRoutingTable.get(mDefaultRoute); |
nxf38293 | 4d174fd | 2018-06-29 13:02:43 +0530 | [diff] [blame] | 322 | if (defaultRouteAids != null) { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 323 | for (String defaultRouteAid : defaultRouteAids) { |
| 324 | // Check whether there are any shorted AIDs routed to non-default |
| 325 | // TODO this is O(N^2) run-time complexity... |
| 326 | for (Map.Entry<String, Integer> aidEntry : mRouteForAid.entrySet()) { |
| 327 | String aid = aidEntry.getKey(); |
| 328 | int route = aidEntry.getValue(); |
| 329 | if (defaultRouteAid.startsWith(aid) && route != mDefaultRoute) { |
| 330 | if (DBG) Log.d(TAG, "Adding AID " + defaultRouteAid + " for default " + |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 331 | "route, because a conflicting shorter AID will be " + |
| 332 | "added to the routing table"); |
| 333 | aidRoutingTableCache.put(defaultRouteAid, aidMap.get(defaultRouteAid)); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 334 | } |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 339 | // Add AID entries for |
| 340 | // 1. all non-default routes |
| 341 | // 2. default route but only payment AID |
Suhas Suresh | ce6a344 | 2018-07-30 21:06:36 +0530 | [diff] [blame] | 342 | // Add AID entries for all non-default routes |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 343 | for (int i = 0; i < mAidRoutingTable.size(); i++) { |
| 344 | int route = mAidRoutingTable.keyAt(i); |
Suhas Suresh | ce6a344 | 2018-07-30 21:06:36 +0530 | [diff] [blame] | 345 | if (route != mDefaultRoute) { |
| 346 | Set<String> aidsForRoute = mAidRoutingTable.get(route); |
| 347 | for (String aid : aidsForRoute) { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 348 | if (aid.endsWith("*")) { |
| 349 | if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) { |
| 350 | Log.e(TAG, "This device does not support prefix AIDs."); |
| 351 | } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY) { |
| 352 | if (DBG) Log.d(TAG, "Routing prefix AID " + aid + " to route " |
| 353 | + Integer.toString(route)); |
| 354 | // Cut off '*' since controller anyway treats all AIDs as a prefix |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 355 | aidRoutingTableCache.put(aid.substring(0,aid.length() - 1), aidMap.get(aid)); |
| 356 | } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX || |
| 357 | mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 358 | if (DBG) Log.d(TAG, "Routing prefix AID " + aid + " to route " |
| 359 | + Integer.toString(route)); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 360 | aidRoutingTableCache.put(aid.substring(0,aid.length() - 1), aidMap.get(aid)); |
nxpandroid | cbf2482 | 2017-07-12 21:37:17 +0530 | [diff] [blame] | 361 | } |
| 362 | } else if (aid.endsWith("#")) { |
| 363 | if (mAidMatchingSupport == AID_MATCHING_EXACT_ONLY) { |
| 364 | Log.e(TAG, "Device does not support subset AIDs but AID [" + aid |
| 365 | + "] is registered"); |
| 366 | } else if (mAidMatchingSupport == AID_MATCHING_PREFIX_ONLY || |
| 367 | mAidMatchingSupport == AID_MATCHING_EXACT_OR_PREFIX) { |
| 368 | Log.e(TAG, "Device does not support subset AIDs but AID [" + aid |
| 369 | + "] is registered"); |
| 370 | } else if (mAidMatchingSupport == AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX) { |
| 371 | if (DBG) Log.d(TAG, "Routing subset AID " + aid + " to route " |
| 372 | + Integer.toString(route)); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 373 | aidRoutingTableCache.put(aid.substring(0,aid.length() - 1), aidMap.get(aid)); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 374 | } |
| 375 | } else { |
| 376 | if (DBG) Log.d(TAG, "Routing exact AID " + aid + " to route " |
| 377 | + Integer.toString(route)); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 378 | aidRoutingTableCache.put(aid, aidMap.get(aid)); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 379 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 380 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 381 | } |
| 382 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 383 | if( calculateAidRouteSize(aidRoutingTableCache) <= mMaxAidRoutingTableSize) { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 384 | aidRouteResolved = true; |
| 385 | break; |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 386 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 387 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 388 | if(aidRouteResolved == true) { |
| 389 | commit(aidRoutingTableCache); |
Ganesh Deva | 49fde92 | 2019-05-21 15:07:33 +0530 | [diff] [blame] | 390 | NfcService.getInstance().updateDefaultAidRoute(mDefaultRoute); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 391 | mLastCommitStatus = true; |
| 392 | } else { |
Ganesh Deva | c90b32d | 2019-07-12 11:53:10 +0530 | [diff] [blame] | 393 | StatsLog.write(StatsLog.NFC_ERROR_OCCURRED, StatsLog.NFC_ERROR_OCCURRED__TYPE__AID_OVERFLOW, 0, 0); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 394 | Log.e(TAG, "RoutingTable unchanged because it's full, not updating"); |
| 395 | NfcService.getInstance().notifyRoutingTableFull(); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 396 | mLastCommitStatus = false; |
| 397 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 398 | } |
Suhas Suresh | 8cd37b3 | 2019-06-25 16:50:16 +0530 | [diff] [blame] | 399 | if (NfcService.getInstance().isNfcEnabled()) |
| 400 | NfcService.getInstance().commitRouting(); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 401 | return true; |
| 402 | } |
| 403 | |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 404 | private void commit(HashMap<String, AidEntry> routeCache ) { |
| 405 | if(routeCache == null) |
| 406 | { |
| 407 | return; |
| 408 | } |
| 409 | for (Map.Entry<String, AidEntry> aidEntry : routeCache.entrySet()) { |
| 410 | if(aidEntry.getKey().isEmpty()) |
| 411 | continue; |
| 412 | AidEntry element = aidEntry.getValue(); |
| 413 | if (DBG) Log.d (TAG, element.toString()); |
| 414 | NfcService.getInstance().routeAids( |
| 415 | aidEntry.getKey(), |
| 416 | element.route, |
| 417 | element.aidInfo, |
| 418 | element.powerstate); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 419 | } |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 420 | AidEntry emptyAidEntry = routeCache.get(""); |
| 421 | if (emptyAidEntry != null) |
| 422 | NfcService.getInstance().routeAids( |
| 423 | "", emptyAidEntry.route, emptyAidEntry.aidInfo, emptyAidEntry.powerstate); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 424 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 425 | /** |
| 426 | * This notifies that the AID routing table in the controller |
| 427 | * has been cleared (usually due to NFC being turned off). |
| 428 | */ |
| 429 | public void onNfccRoutingTableCleared() { |
| 430 | // The routing table in the controller was cleared |
| 431 | // To stay in sync, clear our own tables. |
| 432 | synchronized (mLock) { |
| 433 | mAidRoutingTable.clear(); |
| 434 | mRouteForAid.clear(); |
| 435 | } |
| 436 | } |
| 437 | |
nxpandroid | ebf53fb | 2016-12-22 18:48:59 +0530 | [diff] [blame] | 438 | public boolean getLastCommitRoutingStatus() { |
| 439 | return mLastCommitStatus; |
| 440 | } |
| 441 | |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 442 | public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| 443 | pw.println("Routing table:"); |
| 444 | pw.println(" Default route: " + ((mDefaultRoute == 0x00) ? "host" : "secure element")); |
| 445 | synchronized (mLock) { |
| 446 | for (int i = 0; i < mAidRoutingTable.size(); i++) { |
| 447 | Set<String> aids = mAidRoutingTable.valueAt(i); |
| 448 | pw.println(" Routed to 0x" + Integer.toHexString(mAidRoutingTable.keyAt(i)) + ":"); |
| 449 | for (String aid : aids) { |
| 450 | pw.println(" \"" + aid + "\""); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 451 | } |
| 452 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 453 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 454 | } |
Suryaprakash Konduru | d7f2541 | 2018-04-12 12:24:24 +0530 | [diff] [blame] | 455 | |
| 456 | // Returns true if AppChooserActivity is foreground to restart RF discovery so that |
| 457 | // TapAgainDialog is dismissed when an external reader detects the device. |
| 458 | private boolean isProcessingTapAgain() { |
| 459 | String appChooserActivityClassName = AppChooserActivity.class.getName(); |
| 460 | return appChooserActivityClassName.equals(getTopClass()); |
| 461 | } |
| 462 | |
| 463 | private String getTopClass() { |
| 464 | String topClass = null; |
| 465 | List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1); |
| 466 | if (tasks != null && tasks.size() > 0) { |
| 467 | topClass = tasks.get(0).topActivity.getClassName(); |
| 468 | } |
| 469 | return topClass; |
| 470 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 471 | } |