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