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.sysprop.NfcProperties;
20 import android.util.Log;
21 import android.util.proto.ProtoOutputStream;
22 
23 import com.android.nfc.NfcService;
24 import com.android.nfc.cardemulation.RegisteredT3tIdentifiersCache.T3tIdentifier;
25 
26 import java.io.FileDescriptor;
27 import java.io.PrintWriter;
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 public class SystemCodeRoutingManager {
32     static final String TAG = "SystemCodeRoutingManager";
33 
34     static final boolean DBG = NfcProperties.debug_enabled().orElse(true);
35 
36     final Object mLock = new Object();
37 
38     List<T3tIdentifier> mConfiguredT3tIdentifiers =
39             new ArrayList<T3tIdentifier>();
40 
configureRouting(List<T3tIdentifier> t3tIdentifiers)41     public boolean configureRouting(List<T3tIdentifier> t3tIdentifiers) {
42         if (DBG) Log.d(TAG, "configureRouting");
43         List<T3tIdentifier> toBeAdded = new ArrayList<T3tIdentifier>();
44         List<T3tIdentifier> toBeRemoved = new ArrayList<T3tIdentifier>();
45         synchronized (mLock) {
46             for (T3tIdentifier t3tIdentifier : t3tIdentifiers) {
47                 if (!mConfiguredT3tIdentifiers.contains(t3tIdentifier)) {
48                     toBeAdded.add(t3tIdentifier);
49                 }
50             }
51             for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
52                 if (!t3tIdentifiers.contains(t3tIdentifier)) {
53                     toBeRemoved.add(t3tIdentifier);
54                 }
55             }
56             if (toBeAdded.size() <= 0 && toBeRemoved.size() <= 0) {
57                 Log.d(TAG, "Routing table unchanged, not updating");
58                 return false;
59             }
60             // Update internal structures
61             for (T3tIdentifier t3tIdentifier : toBeRemoved) {
62                 if (DBG) Log.d(TAG, "deregisterNfcFSystemCodeonDh:");
63                 NfcService.getInstance().deregisterT3tIdentifier(
64                         t3tIdentifier.systemCode, t3tIdentifier.nfcid2, t3tIdentifier.t3tPmm);
65             }
66             for (T3tIdentifier t3tIdentifier : toBeAdded) {
67                 if (DBG) Log.d(TAG, "registerNfcFSystemCodeonDh:");
68                 NfcService.getInstance().registerT3tIdentifier(
69                         t3tIdentifier.systemCode, t3tIdentifier.nfcid2 , t3tIdentifier.t3tPmm);
70             }
71             if (DBG) {
72                 Log.d(TAG, "(Before) mConfiguredT3tIdentifiers: size=" +
73                         mConfiguredT3tIdentifiers.size());
74                 for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
75                     Log.d(TAG, "    " + t3tIdentifier.systemCode +
76                             "/" + t3tIdentifier.t3tPmm);
77                 }
78                 Log.d(TAG, "(After) mConfiguredT3tIdentifiers: size=" +
79                         t3tIdentifiers.size());
80                 for (T3tIdentifier t3tIdentifier : t3tIdentifiers) {
81                     Log.d(TAG, "    " + t3tIdentifier.systemCode +
82                             "/" + t3tIdentifier.nfcid2 +
83                             "/" + t3tIdentifier.t3tPmm);
84                 }
85             }
86             mConfiguredT3tIdentifiers = t3tIdentifiers;
87         }
88 
89         // And finally commit the routing
90         NfcService.getInstance().commitRouting();
91 
92         return true;
93     }
94 
95     /**
96      * This notifies that the SystemCode routing table in the controller
97      * has been cleared (usually due to NFC being turned off).
98      */
onNfccRoutingTableCleared()99     public void onNfccRoutingTableCleared() {
100         // The routing table in the controller was cleared
101         // To stay in sync, clear our own tables.
102         synchronized (mLock) {
103             if (DBG) Log.d(TAG, "onNfccRoutingTableCleared");
104             NfcService.getInstance().clearT3tIdentifiersCache();
105             mConfiguredT3tIdentifiers.clear();
106         }
107     }
108 
dump(FileDescriptor fd, PrintWriter pw, String[] args)109     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
110         pw.println("HCE-F routing table:");
111         synchronized (mLock) {
112             for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
113                 pw.println("    " + t3tIdentifier.systemCode +
114                         "/" + t3tIdentifier.nfcid2);
115             }
116         }
117     }
118 
119     /**
120      * Dump debugging information as a SystemCodeRoutingManagerProto
121      *
122      * Note:
123      * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto
124      * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
125      * {@link ProtoOutputStream#end(long)} after.
126      * Never reuse a proto field number. When removing a field, mark it as reserved.
127      */
dumpDebug(ProtoOutputStream proto)128     void dumpDebug(ProtoOutputStream proto) {
129         synchronized (mLock) {
130             for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
131                 long token = proto.start(SystemCodeRoutingManagerProto.T3T_IDENTIFIERS);
132                 proto.write(SystemCodeRoutingManagerProto.T3tIdentifier.SYSTEM_CODE,
133                         t3tIdentifier.systemCode);
134                 proto.write(SystemCodeRoutingManagerProto.T3tIdentifier.NFCID2,
135                         t3tIdentifier.nfcid2);
136                 proto.end(token);
137             }
138         }
139     }
140 }
141