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 java.io.FileDescriptor;
19 import java.io.PrintWriter;
20 
21 import com.android.nfc.ForegroundUtils;
22 
23 import android.app.ActivityManager;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.nfc.cardemulation.NfcFServiceInfo;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.util.Log;
30 
31 public class EnabledNfcFServices implements com.android.nfc.ForegroundUtils.Callback {
32     static final String TAG = "EnabledNfcFCardEmulationServices";
33     static final boolean DBG = false;
34 
35     final Context mContext;
36     final RegisteredNfcFServicesCache mNfcFServiceCache;
37     final RegisteredT3tIdentifiersCache mT3tIdentifiersCache;
38     final Callback mCallback;
39     final ForegroundUtils mForegroundUtils = ForegroundUtils.getInstance();
40     final Handler mHandler = new Handler(Looper.getMainLooper());
41 
42     final Object mLock = new Object();
43     // Variables below synchronized on mLock
44     ComponentName mForegroundComponent = null; // The computed enabled foreground component
45     ComponentName mForegroundRequested = null; // The component requested to be enabled by fg app
46     int mForegroundUid = -1; // The UID of the fg app, or -1 if fg app didn't request
47 
48     boolean mComputeFgRequested = false;
49     boolean mActivated = false;
50 
51     public interface Callback {
onEnabledForegroundNfcFServiceChanged(ComponentName service)52         void onEnabledForegroundNfcFServiceChanged(ComponentName service);
53     }
54 
EnabledNfcFServices(Context context, RegisteredNfcFServicesCache nfcFServiceCache, RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback)55     public EnabledNfcFServices(Context context,
56             RegisteredNfcFServicesCache nfcFServiceCache,
57             RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback) {
58         if (DBG) Log.d(TAG, "EnabledNfcFServices");
59         mContext = context;
60         mNfcFServiceCache = nfcFServiceCache;
61         mT3tIdentifiersCache = t3tIdentifiersCache;
62         mCallback = callback;
63     }
64 
computeEnabledForegroundService()65     void computeEnabledForegroundService() {
66         if (DBG) Log.d(TAG, "computeEnabledForegroundService");
67         ComponentName foregroundRequested = null;
68         boolean changed = false;
69         synchronized (mLock) {
70             if (mActivated) {
71                 Log.d(TAG, "configuration will be postponed until deactivation");
72                 mComputeFgRequested = true;
73                 return;
74             }
75             mComputeFgRequested = false;
76             foregroundRequested = mForegroundRequested;
77             if (mForegroundRequested != null &&
78                     (mForegroundComponent == null ||
79                     !mForegroundRequested.equals(mForegroundComponent))) {
80                 mForegroundComponent = mForegroundRequested;
81                 changed = true;
82             } else if (mForegroundRequested == null && mForegroundComponent != null){
83                 mForegroundComponent = mForegroundRequested;
84                 changed = true;
85             }
86         }
87         // Notify if anything changed
88         if (changed) {
89             mCallback.onEnabledForegroundNfcFServiceChanged(foregroundRequested);
90         }
91     }
92 
onServicesUpdated()93     public void onServicesUpdated() {
94         if (DBG) Log.d(TAG, "onServicesUpdated");
95         // If enabled foreground service is set, remove it
96         boolean changed = false;
97         synchronized (mLock) {
98             if (mForegroundComponent != null) {
99                 Log.d(TAG, "Removing foreground enabled service because of service update.");
100                 mForegroundRequested = null;
101                 mForegroundUid = -1;
102                 changed = true;
103             }
104         }
105         if (changed) {
106             computeEnabledForegroundService();
107         }
108     }
109 
registerEnabledForegroundService(ComponentName service, int callingUid)110     public boolean registerEnabledForegroundService(ComponentName service, int callingUid) {
111         if (DBG) Log.d(TAG, "registerEnabledForegroundService");
112         boolean success = false;
113         synchronized (mLock) {
114             NfcFServiceInfo serviceInfo = mNfcFServiceCache.getService(
115                     ActivityManager.getCurrentUser(), service);
116             if (serviceInfo == null) {
117                 return false;
118             } else {
119                 if (serviceInfo.getSystemCode().equalsIgnoreCase("NULL") ||
120                         serviceInfo.getNfcid2().equalsIgnoreCase("NULL") ||
121                         serviceInfo.getT3tPmm().equalsIgnoreCase("NULL")) {
122                     return false;
123                 }
124             }
125             if (service.equals(mForegroundRequested)) {
126                 Log.e(TAG, "The servcie is already requested to the foreground service.");
127                 return true;
128             }
129             if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) {
130                 mForegroundRequested = service;
131                 mForegroundUid = callingUid;
132                 success = true;
133             } else {
134                 Log.e(TAG, "Calling UID is not in the foreground, ignorning!");
135             }
136         }
137         if (success) {
138             computeEnabledForegroundService();
139         }
140         return success;
141     }
142 
unregisterForegroundService(int uid)143     boolean unregisterForegroundService(int uid) {
144         if (DBG) Log.d(TAG, "unregisterForegroundService");
145         boolean success = false;
146         synchronized (mLock) {
147             if (mForegroundUid == uid) {
148                 mForegroundRequested = null;
149                 mForegroundUid = -1;
150                 success = true;
151             } // else, other UID in foreground
152         }
153         if (success) {
154             computeEnabledForegroundService();
155         }
156         return success;
157     }
158 
unregisteredEnabledForegroundService(int callingUid)159     public boolean unregisteredEnabledForegroundService(int callingUid) {
160         if (DBG) Log.d(TAG, "unregisterEnabledForegroundService");
161         // Verify the calling UID is in the foreground
162         if (mForegroundUtils.isInForeground(callingUid)) {
163             return unregisterForegroundService(callingUid);
164         } else {
165             Log.e(TAG, "Calling UID is not in the foreground, ignorning!");
166             return false;
167         }
168     }
169 
170     @Override
onUidToBackground(int uid)171     public void onUidToBackground(int uid) {
172         if (DBG) Log.d(TAG, "onUidToBackground");
173         unregisterForegroundService(uid);
174     }
175 
onHostEmulationActivated()176     public void onHostEmulationActivated() {
177         if (DBG) Log.d(TAG, "onHostEmulationActivated");
178         synchronized (mLock) {
179             mActivated = true;
180         }
181     }
182 
onHostEmulationDeactivated()183     public void onHostEmulationDeactivated() {
184         if (DBG) Log.d(TAG, "onHostEmulationDeactivated");
185         boolean needComputeFg = false;
186         synchronized (mLock) {
187             mActivated = false;
188             if (mComputeFgRequested) {
189                 needComputeFg = true;
190             }
191         }
192         if (needComputeFg) {
193             Log.d(TAG, "do postponed configuration");
194             computeEnabledForegroundService();
195         }
196     }
197 
onNfcDisabled()198     public void onNfcDisabled() {
199         synchronized (mLock) {
200             mForegroundComponent = null;
201             mForegroundRequested = null;
202             mActivated = false;
203             mComputeFgRequested = false;
204             mForegroundUid = -1;
205         }
206     }
207 
onUserSwitched(int userId)208     public void onUserSwitched(int userId) {
209         synchronized (mLock) {
210             mForegroundComponent = null;
211             mForegroundRequested = null;
212             mActivated = false;
213             mComputeFgRequested = false;
214             mForegroundUid = -1;
215         }
216     }
217 
dump(FileDescriptor fd, PrintWriter pw, String[] args)218     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
219     }
220 }
221