Home | History | Annotate | Download | only in cardemulation
      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  */
     16 package com.android.nfc.cardemulation;
     17 
     18 import android.util.Log;
     19 import android.util.SparseArray;
     20 
     21 import com.android.nfc.NfcService;
     22 
     23 import java.util.HashMap;
     24 import java.util.HashSet;
     25 import java.util.Map;
     26 import java.util.Set;
     27 
     28 public class AidRoutingManager {
     29     static final String TAG = "AidRoutingManager";
     30 
     31     static final boolean DBG = false;
     32 
     33     // This is the default IsoDep protocol route; it means
     34     // that for any AID that needs to be routed to this
     35     // destination, we won't need to add a rule to the routing
     36     // table, because this destination is already the default route.
     37     //
     38     // For Nexus devices, the default route is always 0x00.
     39     static final int DEFAULT_ROUTE = 0x00;
     40 
     41     // For Nexus devices, just a static route to the eSE
     42     // OEMs/Carriers could manually map off-host AIDs
     43     // to the correct eSE/UICC based on state they keep.
     44     static final int DEFAULT_OFFHOST_ROUTE = 0xF4;
     45 
     46     final Object mLock = new Object();
     47 
     48     // mAidRoutingTable contains the current routing table. The index is the route ID.
     49     // The route can include routes to a eSE/UICC.
     50     final SparseArray<Set<String>> mAidRoutingTable = new SparseArray<Set<String>>();
     51 
     52     // Easy look-up what the route is for a certain AID
     53     final HashMap<String, Integer> mRouteForAid = new HashMap<String, Integer>();
     54 
     55     // Whether the routing table is dirty
     56     boolean mDirty;
     57 
     58     public AidRoutingManager() {
     59 
     60     }
     61 
     62     public boolean aidsRoutedToHost() {
     63         synchronized(mLock) {
     64             Set<String> aidsToHost = mAidRoutingTable.get(0);
     65             return aidsToHost != null && aidsToHost.size() > 0;
     66         }
     67     }
     68 
     69     public Set<String> getRoutedAids() {
     70         Set<String> routedAids = new HashSet<String>();
     71         synchronized (mLock) {
     72             for (Map.Entry<String, Integer> aidEntry : mRouteForAid.entrySet()) {
     73                 routedAids.add(aidEntry.getKey());
     74             }
     75         }
     76         return routedAids;
     77     }
     78 
     79     public boolean setRouteForAid(String aid, boolean onHost) {
     80         int route;
     81         synchronized (mLock) {
     82             int currentRoute = getRouteForAidLocked(aid);
     83             if (DBG) Log.d(TAG, "Set route for AID: " + aid + ", host: " + onHost + " , current: 0x" +
     84                     Integer.toHexString(currentRoute));
     85             route = onHost ? 0 : DEFAULT_OFFHOST_ROUTE;
     86             if (route == currentRoute) return true;
     87 
     88             if (currentRoute != -1) {
     89                 // Remove current routing
     90                 removeAid(aid);
     91             }
     92             Set<String> aids = mAidRoutingTable.get(route);
     93             if (aids == null) {
     94                aids = new HashSet<String>();
     95                mAidRoutingTable.put(route, aids);
     96             }
     97             aids.add(aid);
     98             mRouteForAid.put(aid, route);
     99             if (route != DEFAULT_ROUTE) {
    100                 NfcService.getInstance().routeAids(aid, route);
    101                 mDirty = true;
    102             }
    103         }
    104         return true;
    105     }
    106 
    107     /**
    108      * This notifies that the AID routing table in the controller
    109      * has been cleared (usually due to NFC being turned off).
    110      */
    111     public void onNfccRoutingTableCleared() {
    112         // The routing table in the controller was cleared
    113         // To stay in sync, clear our own tables.
    114         synchronized (mLock) {
    115             mAidRoutingTable.clear();
    116             mRouteForAid.clear();
    117         }
    118     }
    119 
    120     public boolean removeAid(String aid) {
    121         synchronized (mLock) {
    122             Integer route = mRouteForAid.get(aid);
    123             if (route == null) {
    124                if (DBG) Log.d(TAG, "removeAid(): No existing route for " + aid);
    125                return false;
    126             }
    127             Set<String> aids = mAidRoutingTable.get(route);
    128             if (aids == null) return false;
    129             aids.remove(aid);
    130             mRouteForAid.remove(aid);
    131             if (route.intValue() != DEFAULT_ROUTE) {
    132                 NfcService.getInstance().unrouteAids(aid);
    133                 mDirty = true;
    134             }
    135         }
    136         return true;
    137     }
    138 
    139     public void commitRouting() {
    140         synchronized (mLock) {
    141             if (mDirty) {
    142                 NfcService.getInstance().commitRouting();
    143                 mDirty = false;
    144             } else {
    145                 if (DBG) Log.d(TAG, "Not committing routing because table not dirty.");
    146             }
    147         }
    148     }
    149 
    150     int getRouteForAidLocked(String aid) {
    151         Integer route = mRouteForAid.get(aid);
    152         return route == null ? -1 : route;
    153     }
    154 }
    155