1 /* 2 * Copyright (C) 2019 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 17 package com.android.server.pm.permission; 18 19 import android.annotation.NonNull; 20 import android.app.ActivityManager; 21 import android.app.ActivityManagerInternal; 22 import android.app.AlarmManager; 23 import android.app.IActivityManager; 24 import android.app.IUidObserver; 25 import android.app.UidObserver; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.pm.PackageManager; 31 import android.os.Handler; 32 import android.os.RemoteException; 33 import android.permission.PermissionControllerManager; 34 import android.provider.DeviceConfig; 35 import android.util.Log; 36 import android.util.SparseArray; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.server.LocalServices; 40 import com.android.server.PermissionThread; 41 42 /** 43 * Class that handles one-time permissions for a user 44 */ 45 public class OneTimePermissionUserManager { 46 47 private static final String LOG_TAG = OneTimePermissionUserManager.class.getSimpleName(); 48 49 private static final boolean DEBUG = false; 50 private static final long DEFAULT_KILLED_DELAY_MILLIS = 5000; 51 public static final String PROPERTY_KILLED_DELAY_CONFIG_KEY = 52 "one_time_permissions_killed_delay_millis"; 53 54 private final @NonNull Context mContext; 55 private final @NonNull IActivityManager mIActivityManager; 56 private final @NonNull ActivityManagerInternal mActivityManagerInternal; 57 private final @NonNull AlarmManager mAlarmManager; 58 private final @NonNull PermissionControllerManager mPermissionControllerManager; 59 60 private final Object mLock = new Object(); 61 62 private final BroadcastReceiver mUninstallListener = new BroadcastReceiver() { 63 @Override 64 public void onReceive(Context context, Intent intent) { 65 if (Intent.ACTION_UID_REMOVED.equals(intent.getAction())) { 66 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 67 PackageInactivityListener listener = mListeners.get(uid); 68 if (listener != null) { 69 if (DEBUG) { 70 Log.d(LOG_TAG, "Removing the inactivity listener for " + uid); 71 } 72 listener.cancel(); 73 mListeners.remove(uid); 74 } 75 } 76 } 77 }; 78 79 /** Maps the uid to the PackageInactivityListener */ 80 @GuardedBy("mLock") 81 private final SparseArray<PackageInactivityListener> mListeners = new SparseArray<>(); 82 private final Handler mHandler; 83 OneTimePermissionUserManager(@onNull Context context)84 OneTimePermissionUserManager(@NonNull Context context) { 85 mContext = context; 86 mIActivityManager = ActivityManager.getService(); 87 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 88 mAlarmManager = context.getSystemService(AlarmManager.class); 89 mPermissionControllerManager = new PermissionControllerManager( 90 mContext, PermissionThread.getHandler()); 91 mHandler = context.getMainThreadHandler(); 92 } 93 startPackageOneTimeSession(@onNull String packageName, long timeoutMillis, long revokeAfterKilledDelayMillis)94 void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis, 95 long revokeAfterKilledDelayMillis) { 96 int uid; 97 try { 98 uid = mContext.getPackageManager().getPackageUid(packageName, 0); 99 } catch (PackageManager.NameNotFoundException e) { 100 Log.e(LOG_TAG, "Unknown package name " + packageName, e); 101 return; 102 } 103 104 synchronized (mLock) { 105 PackageInactivityListener listener = mListeners.get(uid); 106 if (listener != null) { 107 listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis); 108 return; 109 } 110 listener = new PackageInactivityListener(uid, packageName, timeoutMillis, 111 revokeAfterKilledDelayMillis); 112 mListeners.put(uid, listener); 113 } 114 } 115 116 /** 117 * Stops the one-time permission session for the package. The callback to the end of session is 118 * not invoked. If there is no one-time session for the package then nothing happens. 119 * 120 * @param packageName Package to stop the one-time permission session for 121 */ stopPackageOneTimeSession(@onNull String packageName)122 void stopPackageOneTimeSession(@NonNull String packageName) { 123 int uid; 124 try { 125 uid = mContext.getPackageManager().getPackageUid(packageName, 0); 126 } catch (PackageManager.NameNotFoundException e) { 127 Log.e(LOG_TAG, "Unknown package name " + packageName, e); 128 return; 129 } 130 131 synchronized (mLock) { 132 PackageInactivityListener listener = mListeners.get(uid); 133 if (listener != null) { 134 mListeners.remove(uid); 135 listener.cancel(); 136 } 137 } 138 } 139 140 /** 141 * Register to listen for Uids being uninstalled. This must be done outside of the 142 * PermissionManagerService lock. 143 */ registerUninstallListener()144 void registerUninstallListener() { 145 mContext.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED)); 146 } 147 148 /** 149 * A class which watches a package for inactivity and notifies the permission controller when 150 * the package becomes inactive 151 */ 152 private class PackageInactivityListener implements AlarmManager.OnAlarmListener { 153 154 private static final long TIMER_INACTIVE = -1; 155 156 private static final int STATE_GONE = 0; 157 private static final int STATE_TIMER = 1; 158 private static final int STATE_ACTIVE = 2; 159 160 private final int mUid; 161 private final @NonNull String mPackageName; 162 private long mTimeout; 163 private long mRevokeAfterKilledDelay; 164 165 private boolean mIsAlarmSet; 166 private boolean mIsFinished; 167 168 private long mTimerStart = TIMER_INACTIVE; 169 170 private final Object mInnerLock = new Object(); 171 private final Object mToken = new Object(); 172 private final IUidObserver mObserver = new UidObserver() { 173 @Override 174 public void onUidGone(int uid, boolean disabled) { 175 if (uid == mUid) { 176 PackageInactivityListener.this.updateUidState(STATE_GONE); 177 } 178 } 179 180 @Override 181 public void onUidStateChanged(int uid, int procState, long procStateSeq, 182 int capability) { 183 if (uid == mUid) { 184 if (procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE 185 && procState != ActivityManager.PROCESS_STATE_NONEXISTENT) { 186 PackageInactivityListener.this.updateUidState(STATE_TIMER); 187 } else { 188 PackageInactivityListener.this.updateUidState(STATE_ACTIVE); 189 } 190 } 191 } 192 }; 193 PackageInactivityListener(int uid, @NonNull String packageName, long timeout, long revokeAfterkilledDelay)194 private PackageInactivityListener(int uid, @NonNull String packageName, long timeout, 195 long revokeAfterkilledDelay) { 196 Log.i(LOG_TAG, 197 "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout 198 + " killedDelay=" + revokeAfterkilledDelay); 199 200 mUid = uid; 201 mPackageName = packageName; 202 mTimeout = timeout; 203 mRevokeAfterKilledDelay = revokeAfterkilledDelay == -1 204 ? DeviceConfig.getLong( 205 DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY, 206 DEFAULT_KILLED_DELAY_MILLIS) 207 : revokeAfterkilledDelay; 208 209 try { 210 mIActivityManager.registerUidObserver(mObserver, 211 ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_PROCSTATE, 212 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 213 null); 214 } catch (RemoteException e) { 215 Log.e(LOG_TAG, "Couldn't check uid proc state", e); 216 // Can't register uid observer, just revoke immediately 217 synchronized (mInnerLock) { 218 onPackageInactiveLocked(); 219 } 220 } 221 222 updateUidState(); 223 } 224 updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis)225 public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis) { 226 synchronized (mInnerLock) { 227 mTimeout = Math.min(mTimeout, timeoutMillis); 228 mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay, 229 revokeAfterKilledDelayMillis == -1 230 ? DeviceConfig.getLong( 231 DeviceConfig.NAMESPACE_PERMISSIONS, 232 PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS) 233 : revokeAfterKilledDelayMillis); 234 Log.v(LOG_TAG, 235 "Updated params for " + mPackageName + ". timeout=" + mTimeout 236 + " killedDelay=" + mRevokeAfterKilledDelay); 237 updateUidState(); 238 } 239 } 240 getCurrentState()241 private int getCurrentState() { 242 return getStateFromProcState(mActivityManagerInternal.getUidProcessState(mUid)); 243 } 244 getStateFromProcState(int procState)245 private int getStateFromProcState(int procState) { 246 if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) { 247 return STATE_GONE; 248 } else { 249 if (procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { 250 return STATE_TIMER; 251 } else { 252 return STATE_ACTIVE; 253 } 254 } 255 } 256 updateUidState()257 private void updateUidState() { 258 updateUidState(getCurrentState()); 259 } 260 updateUidState(int state)261 private void updateUidState(int state) { 262 Log.v(LOG_TAG, "Updating state for " + mPackageName + " (" + mUid + ")." 263 + " state=" + state); 264 synchronized (mInnerLock) { 265 // Remove any pending inactivity callback 266 mHandler.removeCallbacksAndMessages(mToken); 267 268 if (state == STATE_GONE) { 269 if (mRevokeAfterKilledDelay == 0) { 270 onPackageInactiveLocked(); 271 return; 272 } 273 // Delay revocation in case app is restarting 274 mHandler.postDelayed(() -> { 275 int currentState; 276 synchronized (mInnerLock) { 277 currentState = getCurrentState(); 278 if (currentState == STATE_GONE) { 279 onPackageInactiveLocked(); 280 return; 281 } 282 } 283 if (DEBUG) { 284 Log.d(LOG_TAG, "No longer gone after delayed revocation. " 285 + "Rechecking for " + mPackageName + " (" + mUid 286 + ")."); 287 } 288 updateUidState(currentState); 289 }, mToken, mRevokeAfterKilledDelay); 290 return; 291 } else if (state == STATE_TIMER) { 292 if (mTimerStart == TIMER_INACTIVE) { 293 if (DEBUG) { 294 Log.d(LOG_TAG, "Start the timer for " 295 + mPackageName + " (" + mUid + ")."); 296 } 297 mTimerStart = System.currentTimeMillis(); 298 setAlarmLocked(); 299 } 300 } else if (state == STATE_ACTIVE) { 301 mTimerStart = TIMER_INACTIVE; 302 cancelAlarmLocked(); 303 } 304 } 305 } 306 307 /** 308 * Stop watching the package for inactivity 309 */ cancel()310 private void cancel() { 311 synchronized (mInnerLock) { 312 mIsFinished = true; 313 cancelAlarmLocked(); 314 try { 315 mIActivityManager.unregisterUidObserver(mObserver); 316 } catch (RemoteException e) { 317 Log.e(LOG_TAG, "Unable to unregister uid observer.", e); 318 } 319 } 320 } 321 322 /** 323 * Set the alarm which will callback when the package is inactive 324 */ 325 @GuardedBy("mInnerLock") setAlarmLocked()326 private void setAlarmLocked() { 327 if (mIsAlarmSet) { 328 return; 329 } 330 331 if (DEBUG) { 332 Log.d(LOG_TAG, "Scheduling alarm for " + mPackageName + " (" + mUid + ")."); 333 } 334 long revokeTime = mTimerStart + mTimeout; 335 if (revokeTime > System.currentTimeMillis()) { 336 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, revokeTime, LOG_TAG, this, 337 mHandler); 338 mIsAlarmSet = true; 339 } else { 340 mIsAlarmSet = true; 341 onAlarm(); 342 } 343 } 344 345 /** 346 * Cancel the alarm 347 */ 348 @GuardedBy("mInnerLock") cancelAlarmLocked()349 private void cancelAlarmLocked() { 350 if (mIsAlarmSet) { 351 if (DEBUG) { 352 Log.d(LOG_TAG, "Canceling alarm for " + mPackageName + " (" + mUid + ")."); 353 } 354 mAlarmManager.cancel(this); 355 mIsAlarmSet = false; 356 } 357 } 358 359 /** 360 * Called when the package is considered inactive. This is the end of the session 361 */ 362 @GuardedBy("mInnerLock") onPackageInactiveLocked()363 private void onPackageInactiveLocked() { 364 if (mIsFinished) { 365 return; 366 } 367 if (DEBUG) { 368 Log.d(LOG_TAG, "onPackageInactiveLocked stack trace for " 369 + mPackageName + " (" + mUid + ").", new RuntimeException()); 370 } 371 mIsFinished = true; 372 cancelAlarmLocked(); 373 mHandler.post( 374 () -> { 375 Log.i(LOG_TAG, "One time session expired for " 376 + mPackageName + " (" + mUid + ")."); 377 378 mPermissionControllerManager.notifyOneTimePermissionSessionTimeout( 379 mPackageName); 380 }); 381 try { 382 mIActivityManager.unregisterUidObserver(mObserver); 383 } catch (RemoteException e) { 384 Log.e(LOG_TAG, "Unable to unregister uid observer.", e); 385 } 386 synchronized (mLock) { 387 mListeners.remove(mUid); 388 } 389 } 390 391 @Override onAlarm()392 public void onAlarm() { 393 if (DEBUG) { 394 Log.d(LOG_TAG, "Alarm received for " + mPackageName + " (" + mUid + ")."); 395 } 396 synchronized (mInnerLock) { 397 if (!mIsAlarmSet) { 398 return; 399 } 400 mIsAlarmSet = false; 401 onPackageInactiveLocked(); 402 } 403 } 404 } 405 } 406