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