• 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 package com.android.nfc.cardemulation;
17 
18 import android.app.ActivityManager;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.nfc.cardemulation.NfcFServiceInfo;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.SystemProperties;
25 import android.os.UserHandle;
26 import android.util.Log;
27 import android.util.proto.ProtoOutputStream;
28 
29 import com.android.nfc.ForegroundUtils;
30 
31 import java.io.FileDescriptor;
32 import java.io.PrintWriter;
33 
34 public class EnabledNfcFServices implements com.android.nfc.ForegroundUtils.Callback {
35     static final String TAG = "EnabledNfcFCardEmulationServices";
36     static final boolean DBG = SystemProperties.getBoolean("persist.nfc.debug_enabled", false);
37 
38     final Context mContext;
39     final RegisteredNfcFServicesCache mNfcFServiceCache;
40     final RegisteredT3tIdentifiersCache mT3tIdentifiersCache;
41     final Callback mCallback;
42     final ForegroundUtils mForegroundUtils;
43     final Handler mHandler = new Handler(Looper.getMainLooper());
44 
45     final Object mLock = new Object();
46     // Variables below synchronized on mLock
47     ComponentName mForegroundComponent = null; // The computed enabled foreground component
48     ComponentName mForegroundRequested = null; // The component requested to be enabled by fg app
49     int mForegroundUid = -1; // The UID of the fg app, or -1 if fg app didn't request
50 
51     boolean mComputeFgRequested = false;
52     boolean mActivated = false;
53 
54     public interface Callback {
55         /**
56          * Notify when enabled foreground NfcF service is changed.
57          */
onEnabledForegroundNfcFServiceChanged(int userId, ComponentName service)58         void onEnabledForegroundNfcFServiceChanged(int userId, ComponentName service);
59     }
60 
EnabledNfcFServices(Context context, RegisteredNfcFServicesCache nfcFServiceCache, RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback)61     public EnabledNfcFServices(Context context,
62             RegisteredNfcFServicesCache nfcFServiceCache,
63             RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback) {
64         if (DBG) Log.d(TAG, "EnabledNfcFServices");
65         mContext = context;
66         mForegroundUtils = ForegroundUtils.getInstance(
67                 context.getSystemService(ActivityManager.class));
68         mNfcFServiceCache = nfcFServiceCache;
69         mT3tIdentifiersCache = t3tIdentifiersCache;
70         mCallback = callback;
71     }
72 
computeEnabledForegroundService()73     void computeEnabledForegroundService() {
74         if (DBG) Log.d(TAG, "computeEnabledForegroundService");
75         ComponentName foregroundRequested = null;
76         boolean changed = false;
77         synchronized (mLock) {
78             if (mActivated) {
79                 Log.d(TAG, "configuration will be postponed until deactivation");
80                 mComputeFgRequested = true;
81                 return;
82             }
83             mComputeFgRequested = false;
84             foregroundRequested = mForegroundRequested;
85             if (mForegroundRequested != null &&
86                     (mForegroundComponent == null ||
87                     !mForegroundRequested.equals(mForegroundComponent))) {
88                 mForegroundComponent = mForegroundRequested;
89                 changed = true;
90             } else if (mForegroundRequested == null && mForegroundComponent != null){
91                 mForegroundComponent = mForegroundRequested;
92                 changed = true;
93             }
94         }
95         // Notify if anything changed
96         if (changed) {
97             int userId = UserHandle.getUserHandleForUid(mForegroundUid).getIdentifier();
98             mCallback.onEnabledForegroundNfcFServiceChanged(userId, foregroundRequested);
99         }
100     }
101 
onServicesUpdated()102     public void onServicesUpdated() {
103         if (DBG) Log.d(TAG, "onServicesUpdated");
104         // If enabled foreground service is set, remove it
105         boolean changed = false;
106         synchronized (mLock) {
107             if (mForegroundComponent != null) {
108                 Log.d(TAG, "Removing foreground enabled service because of service update.");
109                 mForegroundRequested = null;
110                 mForegroundUid = -1;
111                 changed = true;
112             }
113         }
114         if (changed) {
115             computeEnabledForegroundService();
116         }
117     }
118 
registerEnabledForegroundService(ComponentName service, int callingUid)119     public boolean registerEnabledForegroundService(ComponentName service, int callingUid) {
120         if (DBG) Log.d(TAG, "registerEnabledForegroundService");
121         boolean success = false;
122         synchronized (mLock) {
123             int userId = UserHandle.getUserHandleForUid(callingUid).getIdentifier();
124             NfcFServiceInfo serviceInfo = mNfcFServiceCache.getService(
125                     userId, service);
126             if (serviceInfo == null) {
127                 return false;
128             } else {
129                 if (serviceInfo.getSystemCode().equalsIgnoreCase("NULL") ||
130                         serviceInfo.getNfcid2().equalsIgnoreCase("NULL") ||
131                         serviceInfo.getT3tPmm().equalsIgnoreCase("NULL")) {
132                     return false;
133                 }
134             }
135             if (service.equals(mForegroundRequested) && mForegroundUid == callingUid) {
136                 Log.e(TAG, "The servcie is already requested to the foreground service.");
137                 return true;
138             }
139             if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) {
140                 mForegroundRequested = service;
141                 mForegroundUid = callingUid;
142                 success = true;
143             } else {
144                 Log.e(TAG, "Calling UID is not in the foreground, ignorning!");
145             }
146         }
147         if (success) {
148             computeEnabledForegroundService();
149         }
150         return success;
151     }
152 
unregisterForegroundService(int uid)153     boolean unregisterForegroundService(int uid) {
154         if (DBG) Log.d(TAG, "unregisterForegroundService");
155         boolean success = false;
156         synchronized (mLock) {
157             if (mForegroundUid == uid) {
158                 mForegroundRequested = null;
159                 mForegroundUid = -1;
160                 success = true;
161             } // else, other UID in foreground
162         }
163         if (success) {
164             computeEnabledForegroundService();
165         }
166         return success;
167     }
168 
unregisteredEnabledForegroundService(int callingUid)169     public boolean unregisteredEnabledForegroundService(int callingUid) {
170         if (DBG) Log.d(TAG, "unregisterEnabledForegroundService");
171         // Verify the calling UID is in the foreground
172         if (mForegroundUtils.isInForeground(callingUid)) {
173             return unregisterForegroundService(callingUid);
174         } else {
175             Log.e(TAG, "Calling UID is not in the foreground, ignorning!");
176             return false;
177         }
178     }
179 
180     @Override
onUidToBackground(int uid)181     public void onUidToBackground(int uid) {
182         if (DBG) Log.d(TAG, "onUidToBackground");
183         unregisterForegroundService(uid);
184     }
185 
onHostEmulationActivated()186     public void onHostEmulationActivated() {
187         if (DBG) Log.d(TAG, "onHostEmulationActivated");
188         synchronized (mLock) {
189             mActivated = true;
190         }
191     }
192 
onHostEmulationDeactivated()193     public void onHostEmulationDeactivated() {
194         if (DBG) Log.d(TAG, "onHostEmulationDeactivated");
195         boolean needComputeFg = false;
196         synchronized (mLock) {
197             mActivated = false;
198             if (mComputeFgRequested) {
199                 needComputeFg = true;
200             }
201         }
202         if (needComputeFg) {
203             Log.d(TAG, "do postponed configuration");
204             computeEnabledForegroundService();
205         }
206     }
207 
onNfcDisabled()208     public void onNfcDisabled() {
209         synchronized (mLock) {
210             mForegroundComponent = null;
211             mForegroundRequested = null;
212             mActivated = false;
213             mComputeFgRequested = false;
214             mForegroundUid = -1;
215         }
216     }
217 
onUserSwitched(int userId)218     public void onUserSwitched(int userId) {
219         synchronized (mLock) {
220             mForegroundComponent = null;
221             mForegroundRequested = null;
222             mActivated = false;
223             mComputeFgRequested = false;
224             mForegroundUid = -1;
225         }
226     }
227 
dump(FileDescriptor fd, PrintWriter pw, String[] args)228     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
229     }
230 
231     /**
232      * Dump debugging information as a EnabledNfcFServicesProto
233      *
234      * Note:
235      * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto
236      * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
237      * {@link ProtoOutputStream#end(long)} after.
238      * Never reuse a proto field number. When removing a field, mark it as reserved.
239      */
dumpDebug(ProtoOutputStream proto)240     void dumpDebug(ProtoOutputStream proto) {
241         synchronized (mLock) {
242             if (mForegroundComponent != null) {
243                 mForegroundComponent.dumpDebug(proto,
244                         EnabledNfcFServicesProto.FOREGROUND_COMPONENT);
245             }
246             if (mForegroundRequested != null) {
247                 mForegroundRequested.dumpDebug(proto,
248                         EnabledNfcFServicesProto.FOREGROUND_REQUESTED);
249             }
250             proto.write(EnabledNfcFServicesProto.ACTIVATED, mActivated);
251             proto.write(EnabledNfcFServicesProto.COMPUTE_FG_REQUESTED, mComputeFgRequested);
252             proto.write(EnabledNfcFServicesProto.FOREGROUND_UID, mForegroundUid);
253         }
254     }
255 }
256