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