• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.nfc.cardemulation;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.nfc.cardemulation.NfcFServiceInfo;
22 import android.os.UserHandle;
23 import android.os.UserManager;
24 import android.sysprop.NfcProperties;
25 import android.util.Log;
26 import android.util.proto.ProtoOutputStream;
27 
28 import java.io.FileDescriptor;
29 import java.io.PrintWriter;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 
36 public class RegisteredT3tIdentifiersCache {
37     static final String TAG = "RegisteredT3tIdentifiersCache";
38 
39     static final boolean DBG = NfcProperties.debug_enabled().orElse(false);
40 
41     // All NFC-F services that have registered
42     final Map<Integer, List<NfcFServiceInfo>> mUserNfcFServiceInfo =
43             new HashMap<Integer, List<NfcFServiceInfo>>();
44 
45     final HashMap<String, NfcFServiceInfo> mForegroundT3tIdentifiersCache =
46             new HashMap<String, NfcFServiceInfo>();
47 
48     ComponentName mEnabledForegroundService;
49     int mEnabledForegroundServiceUserId = -1;
50 
51     final class T3tIdentifier {
52         public final String systemCode;
53         public final String nfcid2;
54         public final String t3tPmm;
55 
T3tIdentifier(String systemCode, String nfcid2, String t3tPmm)56         T3tIdentifier(String systemCode, String nfcid2, String t3tPmm) {
57             this.systemCode = systemCode;
58             this.nfcid2 = nfcid2;
59             this.t3tPmm = t3tPmm;
60         }
61 
62         @Override
equals(Object o)63         public boolean equals(Object o) {
64             if (this == o) return true;
65             if (o == null || getClass() != o.getClass()) return false;
66 
67             T3tIdentifier that = (T3tIdentifier) o;
68             if (!systemCode.equalsIgnoreCase(that.systemCode)) return false;
69             if (!nfcid2.equalsIgnoreCase(that.nfcid2)) return false;
70 
71             return true;
72         }
73 
74         @Override
hashCode()75         public int hashCode() {
76             int result = systemCode.hashCode();
77             result = 31 * result + nfcid2.hashCode();
78             return result;
79         }
80     }
81 
82     final Context mContext;
83     final SystemCodeRoutingManager mRoutingManager;
84 
85     final Object mLock = new Object();
86 
87     boolean mNfcEnabled = false;
88 
RegisteredT3tIdentifiersCache(Context context)89     public RegisteredT3tIdentifiersCache(Context context) {
90         Log.d(TAG, "RegisteredT3tIdentifiersCache");
91         mContext = context;
92         mRoutingManager = new SystemCodeRoutingManager();
93     }
94 
resolveNfcid2(String nfcid2)95     public NfcFServiceInfo resolveNfcid2(String nfcid2) {
96         synchronized (mLock) {
97             if (DBG) Log.d(TAG, "resolveNfcid2: resolving NFCID " + nfcid2);
98             NfcFServiceInfo resolveInfo;
99             resolveInfo = mForegroundT3tIdentifiersCache.get(nfcid2);
100             Log.d(TAG,
101                     "Resolved to: " + (resolveInfo == null ? "null" : resolveInfo.toString()));
102             return resolveInfo;
103         }
104     }
105 
generateUserNfcFServiceInfoLocked(int userId, List<NfcFServiceInfo> services)106     void generateUserNfcFServiceInfoLocked(int userId, List<NfcFServiceInfo> services) {
107         mUserNfcFServiceInfo.put(userId, services);
108     }
109 
getProfileParentId(int userId)110     private int getProfileParentId(int userId) {
111         UserManager um = mContext.createContextAsUser(
112                 UserHandle.of(userId), /*flags=*/0)
113                 .getSystemService(UserManager.class);
114         UserHandle uh = um.getProfileParent(UserHandle.of(userId));
115         return uh == null ? userId : uh.getIdentifier();
116     }
117 
generateForegroundT3tIdentifiersCacheLocked()118     void generateForegroundT3tIdentifiersCacheLocked() {
119         if (DBG) Log.d(TAG, "generateForegroundT3tIdentifiersCacheLocked");
120         mForegroundT3tIdentifiersCache.clear();
121         if (mEnabledForegroundService != null) {
122             for (NfcFServiceInfo service :
123                     mUserNfcFServiceInfo.get(mEnabledForegroundServiceUserId)) {
124                 if (mEnabledForegroundService.equals(service.getComponent())) {
125                     if (!service.getSystemCode().equalsIgnoreCase("NULL") &&
126                             !service.getNfcid2().equalsIgnoreCase("NULL")) {
127                         mForegroundT3tIdentifiersCache.put(service.getNfcid2(), service);
128                     }
129                     break;
130                 }
131             }
132         }
133 
134         if (DBG) {
135             Log.d(TAG, "mForegroundT3tIdentifiersCache: size=" +
136                     mForegroundT3tIdentifiersCache.size());
137             for (Map.Entry<String, NfcFServiceInfo> entry :
138                     mForegroundT3tIdentifiersCache.entrySet()) {
139                 Log.d(TAG, "    " + entry.getKey() +
140                         "/" + entry.getValue().getComponent().toString());
141             }
142         }
143 
144         updateRoutingLocked(false);
145     }
146 
updateRoutingLocked(boolean force)147     void updateRoutingLocked(boolean force) {
148         if (DBG) Log.d(TAG, "updateRoutingLocked");
149         if (!mNfcEnabled) {
150             Log.d(TAG, "Not updating routing table because NFC is off.");
151             return;
152         }
153 
154         List<T3tIdentifier> t3tIdentifiers = new ArrayList<T3tIdentifier>();
155 
156         // Sending an empty table will de-register all entries
157         if (force) {
158             mRoutingManager.configureRouting(t3tIdentifiers);
159         }
160         Iterator<Map.Entry<String, NfcFServiceInfo>> it;
161         // Register foreground service
162         it = mForegroundT3tIdentifiersCache.entrySet().iterator();
163         while (it.hasNext()) {
164             Map.Entry<String, NfcFServiceInfo> entry =
165                     (Map.Entry<String, NfcFServiceInfo>) it.next();
166             t3tIdentifiers.add(new T3tIdentifier(
167                     entry.getValue().getSystemCode(), entry.getValue().getNfcid2(), entry.getValue().getT3tPmm()));
168         }
169         mRoutingManager.configureRouting(t3tIdentifiers);
170     }
171 
onSecureNfcToggled()172     public void onSecureNfcToggled() {
173         synchronized(mLock) {
174             updateRoutingLocked(true);
175       }
176     }
177 
onServicesUpdated(int userId, List<NfcFServiceInfo> services)178     public void onServicesUpdated(int userId, List<NfcFServiceInfo> services) {
179         if (DBG) Log.d(TAG, "onServicesUpdated");
180         synchronized (mLock) {
181             mUserNfcFServiceInfo.put(userId, services);
182         }
183     }
184 
185     /**
186      * Enabled Foreground NfcF service changed
187      */
onEnabledForegroundNfcFServiceChanged(int userId, ComponentName component)188     public void onEnabledForegroundNfcFServiceChanged(int userId, ComponentName component) {
189         if (DBG) Log.d(TAG, "Enabled foreground service changed.");
190         synchronized (mLock) {
191             if (component != null) {
192                 if (mEnabledForegroundService != null
193                         && mEnabledForegroundServiceUserId == userId) {
194                     return;
195                 }
196                 mEnabledForegroundService = component;
197                 mEnabledForegroundServiceUserId = userId;
198             } else {
199                 if (mEnabledForegroundService == null) {
200                     return;
201                 }
202                 mEnabledForegroundService = null;
203                 mEnabledForegroundServiceUserId = -1;
204             }
205             generateForegroundT3tIdentifiersCacheLocked();
206         }
207     }
208 
onNfcEnabled()209     public void onNfcEnabled() {
210         synchronized (mLock) {
211             mNfcEnabled = true;
212         }
213     }
214 
onNfcDisabled()215     public void onNfcDisabled() {
216         synchronized (mLock) {
217             mNfcEnabled = false;
218             mForegroundT3tIdentifiersCache.clear();
219             mEnabledForegroundService = null;
220             mEnabledForegroundServiceUserId = -1;
221         }
222         mRoutingManager.onNfccRoutingTableCleared();
223     }
224 
onUserSwitched()225     public void onUserSwitched() {
226         synchronized (mLock) {
227             mForegroundT3tIdentifiersCache.clear();
228             updateRoutingLocked(false);
229             mEnabledForegroundService = null;
230             mEnabledForegroundServiceUserId = -1;
231         }
232     }
233 
dump(FileDescriptor fd, PrintWriter pw, String[] args)234     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
235         pw.println("T3T Identifier cache entries: ");
236         for (Map.Entry<String, NfcFServiceInfo> entry : mForegroundT3tIdentifiersCache.entrySet()) {
237             pw.println("    NFCID2: " + entry.getKey());
238             pw.println("    NfcFServiceInfo: ");
239             entry.getValue().dump(fd, pw, args);
240         }
241         pw.println("");
242         mRoutingManager.dump(fd, pw, args);
243         pw.println("");
244     }
245 
246     /**
247      * Dump debugging information as a RegisteredT3tIdentifiersCacheProto
248      *
249      * Note:
250      * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto
251      * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
252      * {@link ProtoOutputStream#end(long)} after.
253      * Never reuse a proto field number. When removing a field, mark it as reserved.
254      */
dumpDebug(ProtoOutputStream proto)255     void dumpDebug(ProtoOutputStream proto) {
256         for (NfcFServiceInfo serviceInfo : mForegroundT3tIdentifiersCache.values()) {
257             long token = proto.start(
258                     RegisteredT3tIdentifiersCacheProto.T3T_IDENTIFIER_CACHE_ENTRIES);
259             serviceInfo.dumpDebug(proto);
260             proto.end(token);
261         }
262         long token = proto.start(RegisteredT3tIdentifiersCacheProto.ROUTING_MANAGER);
263         mRoutingManager.dumpDebug(proto);
264         proto.end(token);
265     }
266 }
267