1 /* 2 * Copyright (C) 2018 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.sensorprivacy; 18 19 import static android.Manifest.permission.MANAGE_SENSOR_PRIVACY; 20 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; 21 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; 22 import static android.app.ActivityManager.RunningServiceInfo; 23 import static android.app.ActivityManager.RunningTaskInfo; 24 import static android.app.AppOpsManager.MODE_IGNORED; 25 import static android.app.AppOpsManager.OP_CAMERA; 26 import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA; 27 import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE; 28 import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO; 29 import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO; 30 import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO; 31 import static android.app.AppOpsManager.OP_RECORD_AUDIO; 32 import static android.content.Intent.EXTRA_PACKAGE_NAME; 33 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 34 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; 35 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; 36 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 37 import static android.hardware.SensorPrivacyManager.EXTRA_ALL_SENSORS; 38 import static android.hardware.SensorPrivacyManager.EXTRA_NOTIFICATION_ID; 39 import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR; 40 import static android.hardware.SensorPrivacyManager.EXTRA_TOGGLE_TYPE; 41 import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; 42 import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; 43 import static android.hardware.SensorPrivacyManager.Sources.DIALOG; 44 import static android.hardware.SensorPrivacyManager.Sources.OTHER; 45 import static android.hardware.SensorPrivacyManager.Sources.QS_TILE; 46 import static android.hardware.SensorPrivacyManager.Sources.SETTINGS; 47 import static android.hardware.SensorPrivacyManager.Sources.SHELL; 48 import static android.hardware.SensorPrivacyManager.StateTypes.DISABLED; 49 import static android.hardware.SensorPrivacyManager.StateTypes.ENABLED; 50 import static android.hardware.SensorPrivacyManager.StateTypes.ENABLED_EXCEPT_ALLOWLISTED_APPS; 51 import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_HARDWARE; 52 import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE; 53 import static android.os.UserHandle.USER_NULL; 54 import static android.os.UserHandle.getCallingUserId; 55 import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN; 56 57 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION; 58 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__ACTION_UNKNOWN; 59 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_OFF; 60 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON; 61 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON_EXCEPT_ALLOWLISTED_APPS; 62 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__CAMERA; 63 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__MICROPHONE; 64 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__SENSOR_UNKNOWN; 65 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__DIALOG; 66 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__QS_TILE; 67 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SETTINGS; 68 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; 69 import static com.android.internal.util.FrameworkStatsLog.write; 70 71 import android.Manifest; 72 import android.annotation.FlaggedApi; 73 import android.annotation.NonNull; 74 import android.annotation.Nullable; 75 import android.annotation.RequiresPermission; 76 import android.annotation.UserIdInt; 77 import android.app.ActivityManager; 78 import android.app.ActivityManagerInternal; 79 import android.app.ActivityOptions; 80 import android.app.ActivityTaskManager; 81 import android.app.AppOpsManager; 82 import android.app.AppOpsManagerInternal; 83 import android.app.KeyguardManager; 84 import android.app.Notification; 85 import android.app.NotificationChannel; 86 import android.app.NotificationManager; 87 import android.app.PendingIntent; 88 import android.content.BroadcastReceiver; 89 import android.content.ComponentName; 90 import android.content.Context; 91 import android.content.Intent; 92 import android.content.IntentFilter; 93 import android.content.pm.PackageManager; 94 import android.content.pm.PackageManagerInternal; 95 import android.content.res.Configuration; 96 import android.database.ContentObserver; 97 import android.graphics.drawable.Icon; 98 import android.hardware.ISensorPrivacyListener; 99 import android.hardware.ISensorPrivacyManager; 100 import android.hardware.SensorPrivacyManager; 101 import android.hardware.SensorPrivacyManagerInternal; 102 import android.os.Binder; 103 import android.os.Bundle; 104 import android.os.Handler; 105 import android.os.IBinder; 106 import android.os.Looper; 107 import android.os.Process; 108 import android.os.RemoteCallbackList; 109 import android.os.RemoteException; 110 import android.os.ResultReceiver; 111 import android.os.ShellCallback; 112 import android.os.ShellCommand; 113 import android.os.SystemClock; 114 import android.os.UserHandle; 115 import android.os.UserManager; 116 import android.provider.Settings; 117 import android.safetycenter.SafetyCenterManager; 118 import android.service.voice.VoiceInteractionManagerInternal; 119 import android.telephony.TelephonyCallback; 120 import android.telephony.TelephonyManager; 121 import android.telephony.emergency.EmergencyNumber; 122 import android.text.Html; 123 import android.text.Spanned; 124 import android.text.TextUtils; 125 import android.util.ArrayMap; 126 import android.util.ArraySet; 127 import android.util.IndentingPrintWriter; 128 import android.util.Log; 129 import android.util.Pair; 130 import android.util.proto.ProtoOutputStream; 131 132 import com.android.internal.R; 133 import com.android.internal.annotations.GuardedBy; 134 import com.android.internal.camera.flags.Flags; 135 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 136 import com.android.internal.os.BackgroundThread; 137 import com.android.internal.util.DumpUtils; 138 import com.android.internal.util.FunctionalUtils; 139 import com.android.internal.util.dump.DualDumpOutputStream; 140 import com.android.internal.util.function.pooled.PooledLambda; 141 import com.android.server.FgThread; 142 import com.android.server.LocalServices; 143 import com.android.server.SystemConfig; 144 import com.android.server.SystemService; 145 import com.android.server.pm.UserManagerInternal; 146 147 import java.io.FileDescriptor; 148 import java.io.PrintWriter; 149 import java.util.ArrayList; 150 import java.util.Arrays; 151 import java.util.List; 152 import java.util.NoSuchElementException; 153 import java.util.Objects; 154 155 /** @hide */ 156 public final class SensorPrivacyService extends SystemService { 157 158 private static final String TAG = SensorPrivacyService.class.getSimpleName(); 159 private static final boolean DEBUG = false; 160 private static final boolean DEBUG_LOGGING = false; 161 162 private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE; 163 private static final String ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY = 164 SensorPrivacyService.class.getName() + ".action.disable_sensor_privacy"; 165 166 public static final int REMINDER_DIALOG_DELAY_MILLIS = 500; 167 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 168 private static final int ACTION__TOGGLE_ON = 169 PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON; 170 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 171 private static final int ACTION__TOGGLE_ON_EXCEPT_ALLOWLISTED_APPS = 172 PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON_EXCEPT_ALLOWLISTED_APPS; 173 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 174 private static final int ACTION__TOGGLE_OFF = 175 PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_OFF; 176 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 177 private static final int ACTION__ACTION_UNKNOWN = 178 PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__ACTION_UNKNOWN; 179 private final Context mContext; 180 private final SensorPrivacyServiceImpl mSensorPrivacyServiceImpl; 181 private final UserManagerInternal mUserManagerInternal; 182 private final ActivityManager mActivityManager; 183 private final ActivityManagerInternal mActivityManagerInternal; 184 private final ActivityTaskManager mActivityTaskManager; 185 private final AppOpsManager mAppOpsManager; 186 private final AppOpsManagerInternal mAppOpsManagerInternal; 187 private final TelephonyManager mTelephonyManager; 188 private final PackageManagerInternal mPackageManagerInternal; 189 private final NotificationManager mNotificationManager; 190 private final UserManager mUserManager; 191 192 private CameraPrivacyLightController mCameraPrivacyLightController; 193 194 private final IBinder mAppOpsRestrictionToken = new Binder(); 195 196 private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal; 197 198 private CallStateHelper mCallStateHelper; 199 private KeyguardManager mKeyguardManager; 200 201 List<String> mCameraPrivacyAllowlist = new ArrayList<String>(); 202 203 private int mCurrentUser = USER_NULL; 204 SensorPrivacyService(Context context)205 public SensorPrivacyService(Context context) { 206 super(context); 207 208 mContext = context; 209 mAppOpsManager = context.getSystemService(AppOpsManager.class); 210 mAppOpsManagerInternal = getLocalService(AppOpsManagerInternal.class); 211 mUserManagerInternal = getLocalService(UserManagerInternal.class); 212 mActivityManager = context.getSystemService(ActivityManager.class); 213 mActivityManagerInternal = getLocalService(ActivityManagerInternal.class); 214 mActivityTaskManager = context.getSystemService(ActivityTaskManager.class); 215 mTelephonyManager = context.getSystemService(TelephonyManager.class); 216 mPackageManagerInternal = getLocalService(PackageManagerInternal.class); 217 mNotificationManager = mContext.getSystemService(NotificationManager.class); 218 mUserManager = context.getSystemService(UserManager.class); 219 mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl(); 220 for (String entry : SystemConfig.getInstance().getCameraPrivacyAllowlist()) { 221 mCameraPrivacyAllowlist.add(entry); 222 } 223 } 224 225 @Override onStart()226 public void onStart() { 227 publishBinderService(Context.SENSOR_PRIVACY_SERVICE, mSensorPrivacyServiceImpl); 228 mSensorPrivacyManagerInternal = new SensorPrivacyManagerInternalImpl(); 229 publishLocalService(SensorPrivacyManagerInternal.class, 230 mSensorPrivacyManagerInternal); 231 } 232 233 @Override onBootPhase(int phase)234 public void onBootPhase(int phase) { 235 if (phase == PHASE_SYSTEM_SERVICES_READY) { 236 mKeyguardManager = mContext.getSystemService(KeyguardManager.class); 237 mCallStateHelper = new CallStateHelper(); 238 mSensorPrivacyServiceImpl.registerSettingsObserver(); 239 } else if (phase == PHASE_ACTIVITY_MANAGER_READY) { 240 mCameraPrivacyLightController = new CameraPrivacyLightController(mContext); 241 } 242 } 243 244 @Override onUserStarting(TargetUser user)245 public void onUserStarting(TargetUser user) { 246 if (mCurrentUser == USER_NULL) { 247 mCurrentUser = user.getUserIdentifier(); 248 mSensorPrivacyServiceImpl.userSwitching(USER_NULL, user.getUserIdentifier()); 249 } 250 } 251 252 @Override onUserSwitching(TargetUser from, TargetUser to)253 public void onUserSwitching(TargetUser from, TargetUser to) { 254 mCurrentUser = to.getUserIdentifier(); 255 mSensorPrivacyServiceImpl.userSwitching(from.getUserIdentifier(), to.getUserIdentifier()); 256 } 257 258 class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements 259 AppOpsManager.OnOpNotedInternalListener, AppOpsManager.OnOpStartedListener, 260 IBinder.DeathRecipient, UserManagerInternal.UserRestrictionsListener { 261 262 private final SensorPrivacyHandler mHandler; 263 private final Object mLock = new Object(); 264 265 private SensorPrivacyStateController mSensorPrivacyStateController; 266 267 /** 268 * Packages for which not to show sensor use reminders. 269 * 270 * <Package, User> -> list of suppressor tokens 271 */ 272 @GuardedBy("mLock") 273 private ArrayMap<Pair<Integer, UserHandle>, ArrayList<IBinder>> mSuppressReminders = 274 new ArrayMap<>(); 275 276 private final ArrayMap<SensorUseReminderDialogInfo, ArraySet<Integer>> 277 mQueuedSensorUseReminderDialogs = new ArrayMap<>(); 278 279 private class SensorUseReminderDialogInfo { 280 private int mTaskId; 281 private UserHandle mUser; 282 private String mPackageName; 283 SensorUseReminderDialogInfo(int taskId, UserHandle user, String packageName)284 SensorUseReminderDialogInfo(int taskId, UserHandle user, String packageName) { 285 mTaskId = taskId; 286 mUser = user; 287 mPackageName = packageName; 288 } 289 290 @Override equals(Object o)291 public boolean equals(Object o) { 292 if (this == o) return true; 293 if (o == null || !(o instanceof SensorUseReminderDialogInfo)) return false; 294 SensorUseReminderDialogInfo that = (SensorUseReminderDialogInfo) o; 295 return mTaskId == that.mTaskId 296 && Objects.equals(mUser, that.mUser) 297 && Objects.equals(mPackageName, that.mPackageName); 298 } 299 300 @Override hashCode()301 public int hashCode() { 302 return Objects.hash(mTaskId, mUser, mPackageName); 303 } 304 } 305 SensorPrivacyServiceImpl()306 SensorPrivacyServiceImpl() { 307 mHandler = new SensorPrivacyHandler(FgThread.get().getLooper(), mContext); 308 mSensorPrivacyStateController = SensorPrivacyStateController.getInstance(); 309 310 correctStateIfNeeded(); 311 312 int[] micAndCameraOps = new int[]{OP_RECORD_AUDIO, OP_PHONE_CALL_MICROPHONE, 313 OP_CAMERA, OP_PHONE_CALL_CAMERA, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO}; 314 mAppOpsManager.startWatchingNoted(micAndCameraOps, this); 315 mAppOpsManager.startWatchingStarted(micAndCameraOps, this); 316 317 318 mContext.registerReceiver(new BroadcastReceiver() { 319 @Override 320 public void onReceive(Context context, Intent intent) { 321 setToggleSensorPrivacy( 322 intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class) 323 .getIdentifier(), 324 OTHER, 325 intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), 326 false 327 ); 328 329 int notificationId = 330 intent.getIntExtra(EXTRA_NOTIFICATION_ID, SystemMessage.NOTE_UNKNOWN); 331 if (notificationId != SystemMessage.NOTE_UNKNOWN) { 332 mNotificationManager.cancel(notificationId); 333 } 334 } 335 }, new IntentFilter(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY), 336 MANAGE_SENSOR_PRIVACY, null, Context.RECEIVER_EXPORTED); 337 338 mContext.registerReceiver(new BroadcastReceiver() { 339 @Override 340 public void onReceive(Context context, Intent intent) { 341 mSensorPrivacyStateController.forEachState( 342 (toggleType, userId, sensor, state) -> 343 logSensorPrivacyToggle(OTHER, sensor, state.isEnabled(), 344 state.getLastChange(), true) 345 ); 346 } 347 }, new IntentFilter(Intent.ACTION_SHUTDOWN)); 348 349 mUserManagerInternal.addUserRestrictionsListener(this); 350 351 mSensorPrivacyStateController.setAllSensorPrivacyListener( 352 mHandler, mHandler::handleSensorPrivacyChanged); 353 mSensorPrivacyStateController.setSensorPrivacyListener( 354 mHandler, 355 (toggleType, userId, sensor, state) -> { 356 mHandler.handleSensorPrivacyChanged( 357 userId, toggleType, sensor, state.isEnabled()); 358 if (Flags.cameraPrivacyAllowlist()) { 359 mHandler.handleSensorPrivacyChanged( 360 userId, toggleType, sensor, state.getState()); 361 } 362 }); 363 364 } 365 366 // If sensor privacy is enabled for a sensor, but the device doesn't support sensor privacy 367 // for that sensor, then disable privacy correctStateIfNeeded()368 private void correctStateIfNeeded() { 369 mSensorPrivacyStateController.forEachState((type, user, sensor, state) -> { 370 if (type != TOGGLE_TYPE_SOFTWARE) { 371 return; 372 } 373 if (!supportsSensorToggle(TOGGLE_TYPE_SOFTWARE, sensor) && state.isEnabled()) { 374 setToggleSensorPrivacyUnchecked( 375 TOGGLE_TYPE_SOFTWARE, user, OTHER, sensor, false); 376 } 377 }); 378 } 379 380 @Override onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions)381 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, 382 Bundle prevRestrictions) { 383 // Reset sensor privacy when restriction is added 384 // Note: isValidCallingUser needs to be called before resetting sensor privacy 385 // because DISALLOW_CAMERA_TOGGLE and DISALLOW_MICROPHONE_TOGGLE are applied on 386 // visible background users in Automotive's Multi Display configuration but we don't 387 // allow sensor privacy to be set on a visible background user. 388 if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE) 389 && newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) { 390 if (isValidCallingUser(userId)) { 391 setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA, 392 false); 393 } 394 } 395 if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE) 396 && newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) { 397 if (isValidCallingUser(userId)) { 398 setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE, 399 false); 400 } 401 } 402 } 403 404 @Override onOpStarted(int code, int uid, String packageName, String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result)405 public void onOpStarted(int code, int uid, String packageName, String attributionTag, 406 @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) { 407 onOpNoted(code, uid, packageName, attributionTag, flags, result); 408 } 409 410 @Override onOpNoted(int code, int uid, String packageName, String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result)411 public void onOpNoted(int code, int uid, String packageName, 412 String attributionTag, @AppOpsManager.OpFlags int flags, 413 @AppOpsManager.Mode int result) { 414 if ((flags & AppOpsManager.OP_FLAGS_ALL_TRUSTED) == 0) { 415 return; 416 } 417 418 int sensor; 419 if (result == MODE_IGNORED) { 420 if (code == OP_RECORD_AUDIO || code == OP_PHONE_CALL_MICROPHONE 421 || code == OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO) { 422 sensor = MICROPHONE; 423 } else if (code == OP_CAMERA || code == OP_PHONE_CALL_CAMERA) { 424 sensor = CAMERA; 425 } else { 426 return; 427 } 428 } else { 429 return; 430 } 431 432 final long token = Binder.clearCallingIdentity(); 433 try { 434 onSensorUseStarted(uid, packageName, sensor); 435 } finally { 436 Binder.restoreCallingIdentity(token); 437 } 438 } 439 440 /** 441 * Called when a sensor protected by toggle sensor privacy is attempting to get used. 442 * 443 * @param uid The uid of the app using the sensor 444 * @param packageName The package name of the app using the sensor 445 * @param sensor The sensor that is attempting to be used 446 */ 447 @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) onSensorUseStarted(int uid, String packageName, int sensor)448 private void onSensorUseStarted(int uid, String packageName, int sensor) { 449 UserHandle user = UserHandle.of(mCurrentUser); 450 451 if (Flags.cameraPrivacyAllowlist() && (sensor == CAMERA) && isAutomotive(mContext)) { 452 if (!isCameraPrivacyEnabled(packageName)) { 453 return; 454 } 455 } else if (!isCombinedToggleSensorPrivacyEnabled(sensor)) { 456 return; 457 } 458 459 if (uid == Process.SYSTEM_UID) { 460 // If the system uid is being blamed for sensor access, the ui must be shown 461 // explicitly using SensorPrivacyManager#showSensorUseDialog 462 return; 463 } 464 465 synchronized (mLock) { 466 if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) { 467 Log.d(TAG, 468 "Suppressed sensor privacy reminder for " + packageName + "/" 469 + user); 470 return; 471 } 472 } 473 474 // TODO: Handle reminders with multiple sensors 475 476 // - If we have a likely activity that triggered the sensor use overlay a dialog over 477 // it. This should be the most common case. 478 // - If there is no use visible entity that triggered the sensor don't show anything as 479 // this is - from the point of the user - a background usage 480 // - Otherwise show a notification as we are not quite sure where to display the dialog. 481 482 List<RunningTaskInfo> tasksOfPackageUsingSensor = new ArrayList<>(); 483 484 List<RunningTaskInfo> tasks = mActivityTaskManager.getTasks(Integer.MAX_VALUE); 485 int numTasks = tasks.size(); 486 for (int taskNum = 0; taskNum < numTasks; taskNum++) { 487 RunningTaskInfo task = tasks.get(taskNum); 488 489 if (task.isVisible) { 490 if (task.topActivity.getPackageName().equals(packageName)) { 491 if (task.isFocused) { 492 // There is the one focused activity 493 enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName, 494 sensor); 495 return; 496 } 497 498 tasksOfPackageUsingSensor.add(task); 499 } else if (task.topActivity.flattenToString().equals( 500 getSensorUseActivityName(new ArraySet<>(Arrays.asList(sensor)))) 501 && task.isFocused) { 502 enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName, 503 sensor); 504 } 505 } 506 } 507 508 // TODO: Test this case 509 // There is one or more non-focused activity 510 if (tasksOfPackageUsingSensor.size() == 1) { 511 enqueueSensorUseReminderDialogAsync(tasksOfPackageUsingSensor.get(0).taskId, user, 512 packageName, sensor); 513 return; 514 } else if (tasksOfPackageUsingSensor.size() > 1) { 515 showSensorUseReminderNotification(user, packageName, sensor); 516 return; 517 } 518 519 // TODO: Test this case 520 // Check if there is a foreground service for this package 521 List<RunningServiceInfo> services = mActivityManager.getRunningServices( 522 Integer.MAX_VALUE); 523 int numServices = services.size(); 524 for (int serviceNum = 0; serviceNum < numServices; serviceNum++) { 525 RunningServiceInfo service = services.get(serviceNum); 526 527 if (service.foreground && service.service.getPackageName().equals(packageName)) { 528 showSensorUseReminderNotification(user, packageName, sensor); 529 return; 530 } 531 } 532 533 String inputMethodComponent = Settings.Secure.getStringForUser( 534 mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, 535 user.getIdentifier()); 536 String inputMethodPackageName = null; 537 if (inputMethodComponent != null) { 538 ComponentName component = ComponentName.unflattenFromString(inputMethodComponent); 539 if (component != null) { 540 inputMethodPackageName = component.getPackageName(); 541 } else { 542 Log.w(TAG, "Failed to parse inputMethodComponent: " + inputMethodComponent); 543 } 544 } 545 546 int capability; 547 try { 548 capability = mActivityManagerInternal.getUidCapability(uid); 549 } catch (IllegalArgumentException e) { 550 Log.w(TAG, e); 551 return; 552 } 553 554 if (sensor == MICROPHONE) { 555 VoiceInteractionManagerInternal voiceInteractionManagerInternal = 556 LocalServices.getService(VoiceInteractionManagerInternal.class); 557 if (voiceInteractionManagerInternal != null 558 && voiceInteractionManagerInternal.hasActiveSession(packageName)) { 559 enqueueSensorUseReminderDialogAsync(-1, user, packageName, sensor); 560 return; 561 } 562 563 if (TextUtils.equals(packageName, inputMethodPackageName) 564 && (capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { 565 enqueueSensorUseReminderDialogAsync(-1, user, packageName, sensor); 566 return; 567 } 568 } 569 570 if (sensor == CAMERA && TextUtils.equals(packageName, inputMethodPackageName) 571 && (capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { 572 enqueueSensorUseReminderDialogAsync(-1, user, packageName, sensor); 573 return; 574 } 575 576 Log.i(TAG, packageName + "/" + uid + " started using sensor " + sensor 577 + " but no activity or foreground service was running. The user will not be" 578 + " informed. System components should check if sensor privacy is enabled for" 579 + " the sensor before accessing it."); 580 } 581 582 /** 583 * Show a dialog that informs the user that a sensor use or a blocked sensor started. 584 * The user can then react to this event. 585 * 586 * @param taskId The task this dialog should be overlaid on. 587 * @param user The user of the package using the sensor. 588 * @param packageName The name of the package using the sensor. 589 * @param sensor The sensor that is being used. 590 */ enqueueSensorUseReminderDialogAsync(int taskId, @NonNull UserHandle user, @NonNull String packageName, int sensor)591 private void enqueueSensorUseReminderDialogAsync(int taskId, @NonNull UserHandle user, 592 @NonNull String packageName, int sensor) { 593 mHandler.sendMessage(PooledLambda.obtainMessage( 594 SensorPrivacyServiceImpl::enqueueSensorUseReminderDialog, this, taskId, user, 595 packageName, sensor)); 596 } 597 enqueueSensorUseReminderDialog(int taskId, @NonNull UserHandle user, @NonNull String packageName, int sensor)598 private void enqueueSensorUseReminderDialog(int taskId, @NonNull UserHandle user, 599 @NonNull String packageName, int sensor) { 600 SensorUseReminderDialogInfo info = 601 new SensorUseReminderDialogInfo(taskId, user, packageName); 602 if (!mQueuedSensorUseReminderDialogs.containsKey(info)) { 603 ArraySet<Integer> sensors = new ArraySet<>(); 604 if (sensor == MICROPHONE && mSuppressReminders.containsKey(new Pair<>(CAMERA, user)) 605 || sensor == CAMERA && mSuppressReminders 606 .containsKey(new Pair<>(MICROPHONE, user))) { 607 sensors.add(MICROPHONE); 608 sensors.add(CAMERA); 609 } else { 610 sensors.add(sensor); 611 } 612 mQueuedSensorUseReminderDialogs.put(info, sensors); 613 mHandler.sendMessageDelayed(PooledLambda.obtainMessage( 614 SensorPrivacyServiceImpl::showSensorUserReminderDialog, this, info), 615 REMINDER_DIALOG_DELAY_MILLIS); 616 return; 617 } 618 ArraySet<Integer> sensors = mQueuedSensorUseReminderDialogs.get(info); 619 sensors.add(sensor); 620 } 621 showSensorUserReminderDialog(@onNull SensorUseReminderDialogInfo info)622 private void showSensorUserReminderDialog(@NonNull SensorUseReminderDialogInfo info) { 623 ArraySet<Integer> sensors = mQueuedSensorUseReminderDialogs.get(info); 624 mQueuedSensorUseReminderDialogs.remove(info); 625 if (sensors == null) { 626 Log.e(TAG, "Unable to show sensor use dialog because sensor set is null." 627 + " Was the dialog queue modified from outside the handler thread?"); 628 return; 629 } 630 Intent dialogIntent = new Intent(); 631 dialogIntent.setComponent( 632 ComponentName.unflattenFromString(getSensorUseActivityName(sensors))); 633 634 ActivityOptions options = ActivityOptions.makeBasic(); 635 options.setLaunchTaskId(info.mTaskId); 636 options.setTaskOverlay(true, true); 637 638 dialogIntent.addFlags( 639 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | FLAG_ACTIVITY_NO_USER_ACTION); 640 641 dialogIntent.putExtra(EXTRA_PACKAGE_NAME, info.mPackageName); 642 if (sensors.size() == 1) { 643 dialogIntent.putExtra(EXTRA_SENSOR, sensors.valueAt(0)); 644 } else if (sensors.size() == 2) { 645 dialogIntent.putExtra(EXTRA_ALL_SENSORS, true); 646 } else { 647 // Currently the only cases can be 1 or two 648 Log.e(TAG, "Attempted to show sensor use dialog for " + sensors.size() 649 + " sensors"); 650 return; 651 } 652 mContext.startActivityAsUser(dialogIntent, options.toBundle(), UserHandle.SYSTEM); 653 } 654 655 /** 656 * Get the activity component based on which privacy toggles are enabled. 657 * @param sensors 658 * @return component name to launch 659 */ getSensorUseActivityName(ArraySet<Integer> sensors)660 private String getSensorUseActivityName(ArraySet<Integer> sensors) { 661 for (Integer sensor : sensors) { 662 if (isToggleSensorPrivacyEnabled(TOGGLE_TYPE_HARDWARE, sensor)) { 663 return mContext.getResources().getString( 664 R.string.config_sensorUseStartedActivity_hwToggle); 665 } 666 } 667 return mContext.getResources().getString(R.string.config_sensorUseStartedActivity); 668 } 669 670 /** 671 * Show a notification that informs the user that a sensor use or a blocked sensor started. 672 * The user can then react to this event. 673 * 674 * @param user The user of the package using the sensor. 675 * @param packageName The name of the package using the sensor. 676 * @param sensor The sensor that is being used. 677 */ showSensorUseReminderNotification(@onNull UserHandle user, @NonNull String packageName, int sensor)678 private void showSensorUseReminderNotification(@NonNull UserHandle user, 679 @NonNull String packageName, int sensor) { 680 int iconRes; 681 int messageRes; 682 int notificationId; 683 684 CharSequence packageLabel; 685 try { 686 packageLabel = getUiContext().getPackageManager() 687 .getApplicationInfoAsUser(packageName, 0, user) 688 .loadLabel(mContext.getPackageManager()); 689 } catch (PackageManager.NameNotFoundException e) { 690 Log.e(TAG, "Cannot show sensor use notification for " + packageName); 691 return; 692 } 693 694 if (sensor == MICROPHONE) { 695 iconRes = R.drawable.ic_mic_blocked; 696 messageRes = R.string.sensor_privacy_start_use_mic_notification_content_title; 697 notificationId = SystemMessage.NOTE_UNBLOCK_MIC_TOGGLE; 698 } else { 699 iconRes = R.drawable.ic_camera_blocked; 700 messageRes = R.string.sensor_privacy_start_use_camera_notification_content_title; 701 notificationId = SystemMessage.NOTE_UNBLOCK_CAM_TOGGLE; 702 } 703 704 NotificationChannel channel = new NotificationChannel( 705 SENSOR_PRIVACY_CHANNEL_ID, 706 getUiContext().getString(R.string.sensor_privacy_notification_channel_label), 707 NotificationManager.IMPORTANCE_HIGH); 708 channel.setSound(null, null); 709 channel.setBypassDnd(true); 710 channel.enableVibration(false); 711 channel.setBlockable(false); 712 713 mNotificationManager.createNotificationChannel(channel); 714 715 Icon icon = Icon.createWithResource(getUiContext().getResources(), iconRes); 716 717 String contentTitle = getUiContext().getString(messageRes); 718 Spanned contentText = Html.fromHtml(getUiContext().getString( 719 R.string.sensor_privacy_start_use_notification_content_text, packageLabel), 0); 720 SafetyCenterManager safetyCenterManager = 721 mContext.getSystemService(SafetyCenterManager.class); 722 String action = safetyCenterManager.isSafetyCenterEnabled() 723 ? Settings.ACTION_PRIVACY_CONTROLS : Settings.ACTION_PRIVACY_SETTINGS; 724 725 PendingIntent contentIntent = PendingIntent.getActivity(mContext, sensor, 726 new Intent(action), 727 PendingIntent.FLAG_IMMUTABLE 728 | PendingIntent.FLAG_UPDATE_CURRENT); 729 730 String actionTitle = getUiContext().getString( 731 R.string.sensor_privacy_start_use_dialog_turn_on_button); 732 PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, sensor, 733 new Intent(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY) 734 .setPackage(mContext.getPackageName()) 735 .putExtra(EXTRA_SENSOR, sensor) 736 .putExtra(EXTRA_NOTIFICATION_ID, notificationId) 737 .putExtra(Intent.EXTRA_USER, user), 738 PendingIntent.FLAG_IMMUTABLE 739 | PendingIntent.FLAG_UPDATE_CURRENT); 740 mNotificationManager.notify(notificationId, 741 new Notification.Builder(mContext, SENSOR_PRIVACY_CHANNEL_ID) 742 .setContentTitle(contentTitle) 743 .setContentText(contentText) 744 .setSmallIcon(icon) 745 .addAction(new Notification.Action.Builder(icon, 746 actionTitle, actionIntent).build()) 747 .setContentIntent(contentIntent) 748 .extend(new Notification.TvExtender()) 749 .setTimeoutAfter(isTelevision(mContext) 750 ? /* dismiss immediately */ 1 751 : /* no timeout */ 0) 752 .build()); 753 } 754 showSensorStateChangedActivity(@ensorPrivacyManager.Sensors.Sensor int sensor, @SensorPrivacyManager.ToggleType int toggleType)755 private void showSensorStateChangedActivity(@SensorPrivacyManager.Sensors.Sensor int sensor, 756 @SensorPrivacyManager.ToggleType int toggleType) { 757 String activityName = mContext.getResources().getString( 758 R.string.config_sensorStateChangedActivity); 759 if (TextUtils.isEmpty(activityName)) { 760 return; 761 } 762 763 Intent dialogIntent = new Intent(); 764 dialogIntent.setComponent( 765 ComponentName.unflattenFromString(activityName)); 766 767 ActivityOptions options = ActivityOptions.makeBasic(); 768 options.setTaskOverlay(true, true); 769 770 dialogIntent.addFlags( 771 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | FLAG_ACTIVITY_NO_USER_ACTION); 772 773 dialogIntent.putExtra(EXTRA_SENSOR, sensor); 774 dialogIntent.putExtra(EXTRA_TOGGLE_TYPE, toggleType); 775 mContext.startActivityAsUser(dialogIntent, options.toBundle(), UserHandle.SYSTEM); 776 } 777 isTelevision(Context context)778 private boolean isTelevision(Context context) { 779 int uiMode = context.getResources().getConfiguration().uiMode; 780 return (uiMode & Configuration.UI_MODE_TYPE_MASK) 781 == Configuration.UI_MODE_TYPE_TELEVISION; 782 } 783 isAutomotive(Context context)784 private boolean isAutomotive(Context context) { 785 int uiMode = context.getResources().getConfiguration().uiMode; 786 return (uiMode & Configuration.UI_MODE_TYPE_MASK) 787 == Configuration.UI_MODE_TYPE_CAR; 788 } 789 790 /** 791 * Sets the sensor privacy to the provided state and notifies all listeners of the new 792 * state. 793 */ 794 @Override setSensorPrivacy(boolean enable)795 public void setSensorPrivacy(boolean enable) { 796 enforceManageSensorPrivacyPermission(); 797 798 // Enforce valid calling user on devices that enable visible background users. 799 enforceValidCallingUser(getCallingUserId()); 800 801 mSensorPrivacyStateController.setAllSensorState(enable); 802 } 803 804 @Override setToggleSensorPrivacy(@serIdInt int userId, @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable)805 public void setToggleSensorPrivacy(@UserIdInt int userId, 806 @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) { 807 if (DEBUG) { 808 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 809 + " callingPid=" + Binder.getCallingPid() 810 + " setToggleSensorPrivacy(" 811 + "userId=" + userId 812 + " source=" + source 813 + " sensor=" + sensor 814 + " enable=" + enable 815 + ")"); 816 } 817 818 enforceManageSensorPrivacyPermission(); 819 if (userId == UserHandle.USER_CURRENT) { 820 userId = mCurrentUser; 821 } 822 823 // Enforce valid calling user on devices that enable visible background users. 824 enforceValidCallingUser(userId); 825 826 if (!canChangeToggleSensorPrivacy(userId, sensor)) { 827 return; 828 } 829 if (enable && !supportsSensorToggle(TOGGLE_TYPE_SOFTWARE, sensor)) { 830 // Do not enable sensor privacy if the device doesn't support it 831 return; 832 } 833 834 setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, source, sensor, enable); 835 } 836 837 838 @Override 839 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 840 @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) setToggleSensorPrivacyState(int userId, int source, int sensor, int state)841 public void setToggleSensorPrivacyState(int userId, int source, int sensor, int state) { 842 if (DEBUG) { 843 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 844 + " callingPid=" + Binder.getCallingPid() 845 + " setToggleSensorPrivacyState(" 846 + "userId=" + userId 847 + " source=" + source 848 + " sensor=" + sensor 849 + " state=" + state 850 + ")"); 851 } 852 enforceManageSensorPrivacyPermission(); 853 if (userId == UserHandle.USER_CURRENT) { 854 userId = mCurrentUser; 855 } 856 857 // Enforce valid calling user on devices that enable visible background users. 858 enforceValidCallingUser(userId); 859 860 if (!canChangeToggleSensorPrivacy(userId, sensor)) { 861 return; 862 } 863 if (!supportsSensorToggle(TOGGLE_TYPE_SOFTWARE, sensor)) { 864 // Do not enable sensor privacy if the device doesn't support it. 865 return; 866 } 867 868 setToggleSensorPrivacyStateUnchecked(TOGGLE_TYPE_SOFTWARE, userId, source, sensor, 869 state); 870 } 871 872 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) setToggleSensorPrivacyStateUnchecked(int toggleType, int userId, int source, int sensor, int state)873 private void setToggleSensorPrivacyStateUnchecked(int toggleType, int userId, int source, 874 int sensor, int state) { 875 if (DEBUG) { 876 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 877 + " callingPid=" + Binder.getCallingPid() 878 + " setToggleSensorPrivacyStateUnchecked(" 879 + "userId=" + userId 880 + " source=" + source 881 + " sensor=" + sensor 882 + " state=" + state 883 + ")"); 884 } 885 long[] lastChange = new long[1]; 886 mSensorPrivacyStateController.atomic(() -> { 887 SensorState sensorState = mSensorPrivacyStateController 888 .getState(toggleType, userId, sensor); 889 lastChange[0] = sensorState.getLastChange(); 890 mSensorPrivacyStateController.setState( 891 toggleType, userId, sensor, state, mHandler, 892 changeSuccessful -> { 893 if (changeSuccessful) { 894 if (userId == mUserManagerInternal.getProfileParentId(userId)) { 895 mHandler.sendMessage(PooledLambda.obtainMessage( 896 SensorPrivacyServiceImpl::logSensorPrivacyStateToggle, 897 this, 898 source, sensor, state, lastChange[0], false)); 899 } 900 } 901 }); 902 }); 903 } 904 905 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) logSensorPrivacyStateToggle(int source, int sensor, int state, long lastChange, boolean onShutDown)906 private void logSensorPrivacyStateToggle(int source, int sensor, int state, 907 long lastChange, boolean onShutDown) { 908 long logMins = Math.max(0, (getCurrentTimeMillis() - lastChange) / (1000 * 60)); 909 910 int logAction = ACTION__ACTION_UNKNOWN; 911 if (!onShutDown) { 912 switch(state) { 913 case ENABLED : 914 logAction = ACTION__TOGGLE_OFF; 915 break; 916 case DISABLED : 917 logAction = ACTION__TOGGLE_ON; 918 break; 919 case ENABLED_EXCEPT_ALLOWLISTED_APPS : 920 logAction = ACTION__TOGGLE_ON_EXCEPT_ALLOWLISTED_APPS; 921 break; 922 default : 923 logAction = ACTION__ACTION_UNKNOWN; 924 break; 925 } 926 } 927 928 int logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__SENSOR_UNKNOWN; 929 switch(sensor) { 930 case CAMERA: 931 logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__CAMERA; 932 break; 933 case MICROPHONE: 934 logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__MICROPHONE; 935 break; 936 default: 937 logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__SENSOR_UNKNOWN; 938 break; 939 } 940 941 int logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; 942 switch(source) { 943 case QS_TILE : 944 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__QS_TILE; 945 break; 946 case DIALOG : 947 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__DIALOG; 948 break; 949 case SETTINGS: 950 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SETTINGS; 951 break; 952 default: 953 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; 954 break; 955 } 956 957 if (DEBUG || DEBUG_LOGGING) { 958 Log.d(TAG, "Logging sensor toggle interaction:" + " logSensor=" + logSensor 959 + " logAction=" + logAction + " logSource=" + logSource + " logMins=" 960 + logMins); 961 } 962 write(PRIVACY_SENSOR_TOGGLE_INTERACTION, logSensor, logAction, logSource, logMins); 963 964 } 965 966 @Override 967 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 968 @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) setToggleSensorPrivacyStateForProfileGroup(int userId, int source, int sensor, int state)969 public void setToggleSensorPrivacyStateForProfileGroup(int userId, int source, int sensor, 970 int state) { 971 enforceManageSensorPrivacyPermission(); 972 if (userId == UserHandle.USER_CURRENT) { 973 userId = mCurrentUser; 974 } 975 int parentId = mUserManagerInternal.getProfileParentId(userId); 976 forAllUsers(userId2 -> { 977 if (parentId == mUserManagerInternal.getProfileParentId(userId2)) { 978 setToggleSensorPrivacyState(userId2, source, sensor, state); 979 } 980 }); 981 } 982 983 @Override 984 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 985 @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) getCameraPrivacyAllowlist()986 public List<String> getCameraPrivacyAllowlist() { 987 enforceObserveSensorPrivacyPermission(); 988 return mCameraPrivacyAllowlist; 989 } 990 991 /** 992 * Sets camera privacy allowlist. 993 * @param allowlist List of automotive driver assistance packages for 994 * privacy allowlisting. 995 * @hide 996 */ 997 @Override setCameraPrivacyAllowlist(List<String> allowlist)998 public void setCameraPrivacyAllowlist(List<String> allowlist) { 999 enforceManageSensorPrivacyPermission(); 1000 mCameraPrivacyAllowlist = new ArrayList<>(allowlist); 1001 } 1002 1003 @Override 1004 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 1005 @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) isCameraPrivacyEnabled(String packageName)1006 public boolean isCameraPrivacyEnabled(String packageName) { 1007 if (DEBUG) { 1008 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 1009 + " callingPid=" + Binder.getCallingPid() 1010 + " isCameraPrivacyEnabled(" 1011 + "packageName=" + packageName 1012 + ")"); 1013 } 1014 enforceObserveSensorPrivacyPermission(); 1015 1016 int state = mSensorPrivacyStateController.getState(TOGGLE_TYPE_SOFTWARE, mCurrentUser, 1017 CAMERA).getState(); 1018 if (state == ENABLED) { 1019 return true; 1020 } else if (state == DISABLED) { 1021 return false; 1022 } else if (state == ENABLED_EXCEPT_ALLOWLISTED_APPS) { 1023 for (String entry : mCameraPrivacyAllowlist) { 1024 if (packageName.equals(entry)) { 1025 return false; 1026 } 1027 } 1028 return true; 1029 } 1030 return false; 1031 } 1032 1033 @Override 1034 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) 1035 @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) getToggleSensorPrivacyState(int toggleType, int sensor)1036 public int getToggleSensorPrivacyState(int toggleType, int sensor) { 1037 if (DEBUG) { 1038 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 1039 + " callingPid=" + Binder.getCallingPid() 1040 + " getToggleSensorPrivacyState(" 1041 + "toggleType=" + toggleType 1042 + " sensor=" + sensor 1043 + ")"); 1044 } 1045 enforceObserveSensorPrivacyPermission(); 1046 1047 return mSensorPrivacyStateController.getState(toggleType, mCurrentUser, sensor) 1048 .getState(); 1049 } 1050 setToggleSensorPrivacyUnchecked(int toggleType, int userId, int source, int sensor, boolean enable)1051 private void setToggleSensorPrivacyUnchecked(int toggleType, int userId, int source, 1052 int sensor, boolean enable) { 1053 if (DEBUG) { 1054 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 1055 + " callingPid=" + Binder.getCallingPid() 1056 + " setToggleSensorPrivacyUnchecked(" 1057 + "userId=" + userId 1058 + " source=" + source 1059 + " sensor=" + sensor 1060 + " enable=" + enable 1061 + ")"); 1062 } 1063 final long[] lastChange = new long[1]; 1064 mSensorPrivacyStateController.atomic(() -> { 1065 SensorState sensorState = mSensorPrivacyStateController 1066 .getState(toggleType, userId, sensor); 1067 lastChange[0] = sensorState.getLastChange(); 1068 mSensorPrivacyStateController.setState( 1069 toggleType, userId, sensor, enable, mHandler, 1070 changeSuccessful -> { 1071 if (changeSuccessful) { 1072 if (userId == mUserManagerInternal.getProfileParentId(userId)) { 1073 mHandler.sendMessage(PooledLambda.obtainMessage( 1074 SensorPrivacyServiceImpl::logSensorPrivacyToggle, this, 1075 source, sensor, enable, lastChange[0], false)); 1076 } 1077 } 1078 }); 1079 }); 1080 } 1081 canChangeToggleSensorPrivacy(@serIdInt int userId, int sensor)1082 private boolean canChangeToggleSensorPrivacy(@UserIdInt int userId, int sensor) { 1083 if (sensor == MICROPHONE && mCallStateHelper.isInEmergencyCall()) { 1084 // During emergency call the microphone toggle managed automatically 1085 Log.i(TAG, "Can't change mic toggle during an emergency call"); 1086 return false; 1087 } 1088 1089 if (requiresAuthentication() && mKeyguardManager != null 1090 && mKeyguardManager.isDeviceLocked(userId)) { 1091 Log.i(TAG, "Can't change mic/cam toggle while device is locked"); 1092 return false; 1093 } 1094 1095 if (sensor == MICROPHONE && mUserManagerInternal.getUserRestriction(userId, 1096 UserManager.DISALLOW_MICROPHONE_TOGGLE)) { 1097 Log.i(TAG, "Can't change mic toggle due to admin restriction"); 1098 return false; 1099 } 1100 1101 if (sensor == CAMERA && mUserManagerInternal.getUserRestriction(userId, 1102 UserManager.DISALLOW_CAMERA_TOGGLE)) { 1103 Log.i(TAG, "Can't change camera toggle due to admin restriction"); 1104 return false; 1105 } 1106 return true; 1107 } 1108 logSensorPrivacyToggle(int source, int sensor, boolean enabled, long lastChange, boolean onShutDown)1109 private void logSensorPrivacyToggle(int source, int sensor, boolean enabled, 1110 long lastChange, boolean onShutDown) { 1111 long logMins = Math.max(0, (getCurrentTimeMillis() - lastChange) / (1000 * 60)); 1112 1113 int logAction = -1; 1114 if (onShutDown) { 1115 // TODO ACTION_POWER_OFF_WHILE_(ON/OFF) 1116 if (enabled) { 1117 logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__ACTION_UNKNOWN; 1118 } else { 1119 logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__ACTION_UNKNOWN; 1120 } 1121 } else { 1122 if (enabled) { 1123 logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_OFF; 1124 } else { 1125 logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON; 1126 } 1127 } 1128 1129 int logSensor = -1; 1130 switch(sensor) { 1131 case CAMERA: 1132 logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__CAMERA; 1133 break; 1134 case MICROPHONE: 1135 logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__MICROPHONE; 1136 break; 1137 default: 1138 logSensor = PRIVACY_SENSOR_TOGGLE_INTERACTION__SENSOR__SENSOR_UNKNOWN; 1139 } 1140 1141 int logSource = -1; 1142 switch(source) { 1143 case QS_TILE : 1144 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__QS_TILE; 1145 break; 1146 case DIALOG : 1147 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__DIALOG; 1148 break; 1149 case SETTINGS: 1150 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SETTINGS; 1151 break; 1152 default: 1153 logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; 1154 } 1155 1156 if (DEBUG || DEBUG_LOGGING) { 1157 Log.d(TAG, "Logging sensor toggle interaction:" + " logSensor=" + logSensor 1158 + " logAction=" + logAction + " logSource=" + logSource + " logMins=" 1159 + logMins); 1160 } 1161 write(PRIVACY_SENSOR_TOGGLE_INTERACTION, logSensor, logAction, logSource, logMins); 1162 1163 } 1164 1165 @Override setToggleSensorPrivacyForProfileGroup(@serIdInt int userId, @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable)1166 public void setToggleSensorPrivacyForProfileGroup(@UserIdInt int userId, 1167 @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) { 1168 enforceManageSensorPrivacyPermission(); 1169 if (userId == UserHandle.USER_CURRENT) { 1170 userId = mCurrentUser; 1171 } 1172 int parentId = mUserManagerInternal.getProfileParentId(userId); 1173 forAllUsers(userId2 -> { 1174 if (parentId == mUserManagerInternal.getProfileParentId(userId2)) { 1175 setToggleSensorPrivacy(userId2, source, sensor, enable); 1176 } 1177 }); 1178 } 1179 1180 // This method enforces valid calling user on devices that enable visible background users. 1181 // Only system user or current user or the user that belongs to the same profile group 1182 // as the current user is permitted to toggle sensor privacy. 1183 // Visible background users are not permitted to toggle sensor privacy. enforceValidCallingUser(@serIdInt int userId)1184 private void enforceValidCallingUser(@UserIdInt int userId) { 1185 if (!isValidCallingUser(userId)) { 1186 throw new SecurityException("User " + userId 1187 + " is not permitted to toggle sensor privacy"); 1188 } 1189 } 1190 isValidCallingUser(@serIdInt int userId)1191 private boolean isValidCallingUser(@UserIdInt int userId) { 1192 // Check whether visible background users are enabled. 1193 // Visible background users are non current but can have UI access. 1194 // The main use case for visible background users is the passenger in Automotive's 1195 // Multi-Display configuration. 1196 if (!UserManager.isVisibleBackgroundUsersEnabled()) { 1197 return true; 1198 } 1199 1200 if (userId == UserHandle.USER_SYSTEM || userId == mCurrentUser) { 1201 return true; 1202 } 1203 1204 final long ident = Binder.clearCallingIdentity(); 1205 try { 1206 if (mUserManager.isSameProfileGroup(userId, mCurrentUser)) { 1207 return true; 1208 } 1209 } finally { 1210 Binder.restoreCallingIdentity(ident); 1211 } 1212 1213 return false; 1214 } 1215 1216 /** 1217 * Enforces the caller contains the necessary permission to change the state of sensor 1218 * privacy. 1219 */ 1220 @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) enforceManageSensorPrivacyPermission()1221 private void enforceManageSensorPrivacyPermission() { 1222 if (mContext.checkCallingOrSelfPermission( 1223 android.Manifest.permission.MANAGE_SENSOR_PRIVACY) == PERMISSION_GRANTED) { 1224 return; 1225 } 1226 1227 String message = "Changing sensor privacy requires the following permission: " 1228 + MANAGE_SENSOR_PRIVACY; 1229 throw new SecurityException(message); 1230 } 1231 1232 /** 1233 * Enforces the caller contains the necessary permission to observe changes to the sate of 1234 * sensor privacy. 1235 */ 1236 @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) enforceObserveSensorPrivacyPermission()1237 private void enforceObserveSensorPrivacyPermission() { 1238 String systemUIPackage = mContext.getString(R.string.config_systemUi); 1239 int systemUIAppId = UserHandle.getAppId(mPackageManagerInternal 1240 .getPackageUid(systemUIPackage, MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM)); 1241 if (UserHandle.getCallingAppId() == systemUIAppId) { 1242 // b/221782106, possible race condition with role grant might bootloop device. 1243 return; 1244 } 1245 if (mContext.checkCallingOrSelfPermission( 1246 android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) == PERMISSION_GRANTED) { 1247 return; 1248 } 1249 1250 String message = "Observing sensor privacy changes requires the following permission: " 1251 + android.Manifest.permission.OBSERVE_SENSOR_PRIVACY; 1252 throw new SecurityException(message); 1253 } 1254 1255 /** 1256 * Returns whether sensor privacy is enabled. 1257 */ 1258 @Override isSensorPrivacyEnabled()1259 public boolean isSensorPrivacyEnabled() { 1260 enforceObserveSensorPrivacyPermission(); 1261 return mSensorPrivacyStateController.getAllSensorState(); 1262 } 1263 1264 @Override isToggleSensorPrivacyEnabled(int toggleType, int sensor)1265 public boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor) { 1266 if (DEBUG) { 1267 Log.d(TAG, "callingUid=" + Binder.getCallingUid() 1268 + " callingPid=" + Binder.getCallingPid() 1269 + " isToggleSensorPrivacyEnabled(" 1270 + "toggleType=" + toggleType 1271 + " sensor=" + sensor 1272 + ")"); 1273 } 1274 enforceObserveSensorPrivacyPermission(); 1275 1276 return mSensorPrivacyStateController.getState(toggleType, mCurrentUser, sensor) 1277 .isEnabled(); 1278 } 1279 1280 @Override isCombinedToggleSensorPrivacyEnabled(int sensor)1281 public boolean isCombinedToggleSensorPrivacyEnabled(int sensor) { 1282 return isToggleSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor) 1283 || isToggleSensorPrivacyEnabled(TOGGLE_TYPE_HARDWARE, sensor); 1284 } 1285 isToggleSensorPrivacyEnabledInternal(int userId, int toggleType, int sensor)1286 private boolean isToggleSensorPrivacyEnabledInternal(int userId, int toggleType, 1287 int sensor) { 1288 1289 return mSensorPrivacyStateController.getState(toggleType, 1290 userId, sensor).isEnabled(); 1291 } 1292 1293 @Override supportsSensorToggle(int toggleType, int sensor)1294 public boolean supportsSensorToggle(int toggleType, int sensor) { 1295 if (toggleType == TOGGLE_TYPE_SOFTWARE) { 1296 if (sensor == MICROPHONE) { 1297 return mContext.getResources() 1298 .getBoolean(R.bool.config_supportsMicToggle); 1299 } else if (sensor == CAMERA) { 1300 return mContext.getResources() 1301 .getBoolean(R.bool.config_supportsCamToggle); 1302 } 1303 } else if (toggleType == TOGGLE_TYPE_HARDWARE) { 1304 if (sensor == MICROPHONE) { 1305 return mContext.getResources() 1306 .getBoolean(R.bool.config_supportsHardwareMicToggle); 1307 } else if (sensor == CAMERA) { 1308 return mContext.getResources() 1309 .getBoolean(R.bool.config_supportsHardwareCamToggle); 1310 } 1311 } 1312 throw new IllegalArgumentException("Invalid arguments. " 1313 + "toggleType=" + toggleType + " sensor=" + sensor); 1314 } 1315 1316 /** 1317 * Registers a listener to be notified when the sensor privacy state changes. 1318 */ 1319 @Override addSensorPrivacyListener(ISensorPrivacyListener listener)1320 public void addSensorPrivacyListener(ISensorPrivacyListener listener) { 1321 enforceObserveSensorPrivacyPermission(); 1322 if (listener == null) { 1323 throw new NullPointerException("listener cannot be null"); 1324 } 1325 mHandler.addListener(listener); 1326 } 1327 1328 /** 1329 * Registers a listener to be notified when the sensor privacy state changes. 1330 */ 1331 @Override addToggleSensorPrivacyListener(ISensorPrivacyListener listener)1332 public void addToggleSensorPrivacyListener(ISensorPrivacyListener listener) { 1333 enforceObserveSensorPrivacyPermission(); 1334 if (listener == null) { 1335 throw new IllegalArgumentException("listener cannot be null"); 1336 } 1337 mHandler.addToggleListener(listener); 1338 } 1339 1340 /** 1341 * Unregisters a listener from sensor privacy state change notifications. 1342 */ 1343 @Override removeSensorPrivacyListener(ISensorPrivacyListener listener)1344 public void removeSensorPrivacyListener(ISensorPrivacyListener listener) { 1345 enforceObserveSensorPrivacyPermission(); 1346 if (listener == null) { 1347 throw new NullPointerException("listener cannot be null"); 1348 } 1349 mHandler.removeListener(listener); 1350 } 1351 1352 /** 1353 * Unregisters a listener from sensor privacy state change notifications. 1354 */ 1355 @Override removeToggleSensorPrivacyListener(ISensorPrivacyListener listener)1356 public void removeToggleSensorPrivacyListener(ISensorPrivacyListener listener) { 1357 enforceObserveSensorPrivacyPermission(); 1358 if (listener == null) { 1359 throw new IllegalArgumentException("listener cannot be null"); 1360 } 1361 mHandler.removeToggleListener(listener); 1362 } 1363 1364 @Override suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token, boolean suppress)1365 public void suppressToggleSensorPrivacyReminders(int userId, int sensor, 1366 IBinder token, boolean suppress) { 1367 enforceManageSensorPrivacyPermission(); 1368 if (userId == UserHandle.USER_CURRENT) { 1369 userId = mCurrentUser; 1370 } 1371 Objects.requireNonNull(token); 1372 1373 Pair<Integer, UserHandle> key = new Pair<>(sensor, UserHandle.of(userId)); 1374 1375 synchronized (mLock) { 1376 if (suppress) { 1377 try { 1378 token.linkToDeath(this, 0); 1379 } catch (RemoteException e) { 1380 Log.e(TAG, "Could not suppress sensor use reminder", e); 1381 return; 1382 } 1383 1384 ArrayList<IBinder> suppressPackageReminderTokens = mSuppressReminders.get(key); 1385 if (suppressPackageReminderTokens == null) { 1386 suppressPackageReminderTokens = new ArrayList<>(1); 1387 mSuppressReminders.put(key, suppressPackageReminderTokens); 1388 } 1389 1390 suppressPackageReminderTokens.add(token); 1391 } else { 1392 mHandler.removeSuppressPackageReminderToken(key, token); 1393 } 1394 } 1395 } 1396 1397 @Override requiresAuthentication()1398 public boolean requiresAuthentication() { 1399 enforceObserveSensorPrivacyPermission(); 1400 return mContext.getResources() 1401 .getBoolean(R.bool.config_sensorPrivacyRequiresAuthentication); 1402 } 1403 1404 @Override showSensorUseDialog(int sensor)1405 public void showSensorUseDialog(int sensor) { 1406 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 1407 throw new SecurityException("Can only be called by the system uid"); 1408 } 1409 if (!isCombinedToggleSensorPrivacyEnabled(sensor)) { 1410 return; 1411 } 1412 enqueueSensorUseReminderDialogAsync( 1413 -1, UserHandle.of(mCurrentUser), "android", sensor); 1414 } 1415 userSwitching(int from, int to)1416 private void userSwitching(int from, int to) { 1417 final boolean[] micState = new boolean[2]; 1418 final boolean[] camState = new boolean[2]; 1419 final boolean[] prevMicState = new boolean[2]; 1420 final boolean[] prevCamState = new boolean[2]; 1421 final int swToggleIdx = 0; 1422 final int hwToggleIdx = 1; 1423 // Get SW toggles state 1424 mSensorPrivacyStateController.atomic(() -> { 1425 prevMicState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, 1426 TOGGLE_TYPE_SOFTWARE, MICROPHONE); 1427 prevCamState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, 1428 TOGGLE_TYPE_SOFTWARE, CAMERA); 1429 micState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, 1430 TOGGLE_TYPE_SOFTWARE, MICROPHONE); 1431 camState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, 1432 TOGGLE_TYPE_SOFTWARE, CAMERA); 1433 }); 1434 // Get HW toggles state 1435 mSensorPrivacyStateController.atomic(() -> { 1436 prevMicState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, 1437 TOGGLE_TYPE_HARDWARE, MICROPHONE); 1438 prevCamState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, 1439 TOGGLE_TYPE_HARDWARE, CAMERA); 1440 micState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, 1441 TOGGLE_TYPE_HARDWARE, MICROPHONE); 1442 camState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, 1443 TOGGLE_TYPE_HARDWARE, CAMERA); 1444 }); 1445 1446 if (from == USER_NULL || prevMicState[swToggleIdx] != micState[swToggleIdx] 1447 || prevMicState[hwToggleIdx] != micState[hwToggleIdx]) { 1448 mHandler.handleSensorPrivacyChanged(to, TOGGLE_TYPE_SOFTWARE, MICROPHONE, 1449 micState[swToggleIdx]); 1450 mHandler.handleSensorPrivacyChanged(to, TOGGLE_TYPE_HARDWARE, MICROPHONE, 1451 micState[hwToggleIdx]); 1452 setGlobalRestriction(MICROPHONE, micState[swToggleIdx] || micState[hwToggleIdx]); 1453 } 1454 if (from == USER_NULL || prevCamState[swToggleIdx] != camState[swToggleIdx] 1455 || prevCamState[hwToggleIdx] != camState[hwToggleIdx]) { 1456 mHandler.handleSensorPrivacyChanged(to, TOGGLE_TYPE_SOFTWARE, CAMERA, 1457 camState[swToggleIdx]); 1458 mHandler.handleSensorPrivacyChanged(to, TOGGLE_TYPE_HARDWARE, CAMERA, 1459 camState[hwToggleIdx]); 1460 setGlobalRestriction(CAMERA, camState[swToggleIdx] || camState[hwToggleIdx]); 1461 } 1462 } 1463 setGlobalRestriction(int sensor, boolean enabled)1464 private void setGlobalRestriction(int sensor, boolean enabled) { 1465 switch(sensor) { 1466 case MICROPHONE: 1467 mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled, 1468 mAppOpsRestrictionToken); 1469 mAppOpsManagerInternal.setGlobalRestriction( 1470 OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, enabled, mAppOpsRestrictionToken); 1471 mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled, 1472 mAppOpsRestrictionToken); 1473 // We don't show the dialog for RECEIVE_SOUNDTRIGGER_AUDIO, but still want to 1474 // restrict it when the microphone is disabled 1475 mAppOpsManagerInternal.setGlobalRestriction(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, 1476 enabled, mAppOpsRestrictionToken); 1477 1478 // Set restriction for OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO 1479 boolean allowed = (Settings.Global.getInt(mContext.getContentResolver(), 1480 Settings.Global.RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO_ENABLED, 1) 1481 == 1); 1482 mAppOpsManagerInternal.setGlobalRestriction( 1483 OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, enabled && !allowed, 1484 mAppOpsRestrictionToken); 1485 break; 1486 case CAMERA: 1487 mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled, 1488 mAppOpsRestrictionToken); 1489 mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_CAMERA, enabled, 1490 mAppOpsRestrictionToken); 1491 break; 1492 } 1493 } 1494 1495 /** 1496 * Remove a sensor use reminder suppression token. 1497 * 1498 * @param key Key the token is in 1499 * @param token The token to remove 1500 */ removeSuppressPackageReminderToken(@onNull Pair<Integer, UserHandle> key, @NonNull IBinder token)1501 private void removeSuppressPackageReminderToken(@NonNull Pair<Integer, UserHandle> key, 1502 @NonNull IBinder token) { 1503 synchronized (mLock) { 1504 ArrayList<IBinder> suppressPackageReminderTokens = 1505 mSuppressReminders.get(key); 1506 if (suppressPackageReminderTokens == null) { 1507 Log.e(TAG, "No tokens for " + key); 1508 return; 1509 } 1510 1511 boolean wasRemoved = suppressPackageReminderTokens.remove(token); 1512 if (wasRemoved) { 1513 token.unlinkToDeath(this, 0); 1514 1515 if (suppressPackageReminderTokens.isEmpty()) { 1516 mSuppressReminders.remove(key); 1517 } 1518 } else { 1519 Log.w(TAG, "Could not remove sensor use reminder suppression token " + token 1520 + " from " + key); 1521 } 1522 } 1523 } 1524 registerSettingsObserver()1525 private void registerSettingsObserver() { 1526 mContext.getContentResolver().registerContentObserver( 1527 Settings.Global.getUriFor( 1528 Settings.Global.RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO_ENABLED), 1529 false, new ContentObserver(mHandler) { 1530 @Override 1531 public void onChange(boolean selfChange) { 1532 setGlobalRestriction(MICROPHONE, 1533 isCombinedToggleSensorPrivacyEnabled(MICROPHONE)); 1534 } 1535 }); 1536 } 1537 1538 /** 1539 * A owner of a suppressor token died. Clean up. 1540 * 1541 * @param token The token that is invalid now. 1542 */ 1543 @Override binderDied(@onNull IBinder token)1544 public void binderDied(@NonNull IBinder token) { 1545 synchronized (mLock) { 1546 for (Pair<Integer, UserHandle> key : mSuppressReminders.keySet()) { 1547 removeSuppressPackageReminderToken(key, token); 1548 } 1549 } 1550 } 1551 1552 @Override binderDied()1553 public void binderDied() { 1554 // Handled in binderDied(IBinder) 1555 } 1556 1557 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1558 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1559 Objects.requireNonNull(fd); 1560 1561 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 1562 1563 int opti = 0; 1564 boolean dumpAsProto = false; 1565 while (opti < args.length) { 1566 String opt = args[opti]; 1567 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { 1568 break; 1569 } 1570 opti++; 1571 if ("--proto".equals(opt)) { 1572 dumpAsProto = true; 1573 } else { 1574 pw.println("Unknown argument: " + opt + "; use -h for help"); 1575 } 1576 } 1577 1578 final long identity = Binder.clearCallingIdentity(); 1579 try { 1580 if (dumpAsProto) { 1581 mSensorPrivacyStateController.dump( 1582 new DualDumpOutputStream(new ProtoOutputStream(fd))); 1583 } else { 1584 pw.println("SENSOR PRIVACY MANAGER STATE (dumpsys " 1585 + Context.SENSOR_PRIVACY_SERVICE + ")"); 1586 1587 mSensorPrivacyStateController.dump( 1588 new DualDumpOutputStream(new IndentingPrintWriter(pw, " "))); 1589 } 1590 } finally { 1591 Binder.restoreCallingIdentity(identity); 1592 } 1593 } 1594 1595 /** 1596 * Convert a string into a {@link SensorPrivacyManager.Sensors.Sensor id}. 1597 * 1598 * @param sensor The name to convert 1599 * 1600 * @return The id corresponding to the name 1601 */ sensorStrToId(@ullable String sensor)1602 private @SensorPrivacyManager.Sensors.Sensor int sensorStrToId(@Nullable String sensor) { 1603 if (sensor == null) { 1604 return UNKNOWN; 1605 } 1606 1607 switch (sensor) { 1608 case "microphone": 1609 return MICROPHONE; 1610 case "camera": 1611 return CAMERA; 1612 default: { 1613 return UNKNOWN; 1614 } 1615 } 1616 } 1617 1618 @Override 1619 @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1620 public void onShellCommand(FileDescriptor in, FileDescriptor out, 1621 FileDescriptor err, String[] args, ShellCallback callback, 1622 ResultReceiver resultReceiver) { 1623 (new ShellCommand() { 1624 @Override 1625 @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) 1626 public int onCommand(String cmd) { 1627 if (cmd == null) { 1628 return handleDefaultCommands(cmd); 1629 } 1630 1631 int userId = Integer.parseInt(getNextArgRequired()); 1632 1633 final PrintWriter pw = getOutPrintWriter(); 1634 switch (cmd) { 1635 case "enable" : { 1636 int sensor = sensorStrToId(getNextArgRequired()); 1637 if (sensor == UNKNOWN) { 1638 pw.println("Invalid sensor"); 1639 return -1; 1640 } 1641 1642 setToggleSensorPrivacy(userId, SHELL, sensor, true); 1643 } 1644 break; 1645 case "disable" : { 1646 int sensor = sensorStrToId(getNextArgRequired()); 1647 if (sensor == UNKNOWN) { 1648 pw.println("Invalid sensor"); 1649 return -1; 1650 } 1651 1652 setToggleSensorPrivacy(userId, SHELL, sensor, false); 1653 } 1654 break; 1655 case "enable_except_allowlisted_apps" : { 1656 if (Flags.cameraPrivacyAllowlist()) { 1657 int sensor = sensorStrToId(getNextArgRequired()); 1658 if ((!isAutomotive(mContext)) || (sensor != CAMERA)) { 1659 pw.println("Command not valid for this sensor"); 1660 return -1; 1661 } 1662 1663 setToggleSensorPrivacyState(userId, SHELL, sensor, 1664 ENABLED_EXCEPT_ALLOWLISTED_APPS); 1665 } 1666 } 1667 break; 1668 default: 1669 return handleDefaultCommands(cmd); 1670 } 1671 1672 return 0; 1673 } 1674 1675 @Override 1676 public void onHelp() { 1677 final PrintWriter pw = getOutPrintWriter(); 1678 1679 pw.println("Sensor privacy manager (" + Context.SENSOR_PRIVACY_SERVICE 1680 + ") commands:"); 1681 pw.println(" help"); 1682 pw.println(" Print this help text."); 1683 pw.println(""); 1684 pw.println(" enable USER_ID SENSOR"); 1685 pw.println(" Enable privacy for a certain sensor."); 1686 pw.println(""); 1687 pw.println(" disable USER_ID SENSOR"); 1688 pw.println(" Disable privacy for a certain sensor."); 1689 pw.println(""); 1690 if (Flags.cameraPrivacyAllowlist()) { 1691 if (isAutomotive(mContext)) { 1692 pw.println(" enable_except_allowlisted_apps " 1693 + "USER_ID SENSOR"); 1694 pw.println(" Enable privacy except for automotive apps which are " 1695 + "required by OEM."); 1696 pw.println(""); 1697 } 1698 } 1699 } 1700 }).exec(this, in, out, err, args, callback, resultReceiver); 1701 } 1702 } 1703 1704 /** 1705 * Handles sensor privacy state changes and notifying listeners of the change. 1706 */ 1707 private final class SensorPrivacyHandler extends Handler { 1708 private static final int MESSAGE_SENSOR_PRIVACY_CHANGED = 1; 1709 1710 private final Object mListenerLock = new Object(); 1711 1712 @GuardedBy("mListenerLock") 1713 private final RemoteCallbackList<ISensorPrivacyListener> mListeners = 1714 new RemoteCallbackList<>(); 1715 @GuardedBy("mListenerLock") 1716 private final RemoteCallbackList<ISensorPrivacyListener> 1717 mToggleSensorListeners = new RemoteCallbackList<>(); 1718 @GuardedBy("mListenerLock") 1719 private final ArrayMap<ISensorPrivacyListener, Pair<DeathRecipient, Integer>> 1720 mDeathRecipients; 1721 private final Context mContext; 1722 SensorPrivacyHandler(Looper looper, Context context)1723 SensorPrivacyHandler(Looper looper, Context context) { 1724 super(looper); 1725 mDeathRecipients = new ArrayMap<>(); 1726 mContext = context; 1727 } 1728 addListener(ISensorPrivacyListener listener)1729 public void addListener(ISensorPrivacyListener listener) { 1730 synchronized (mListenerLock) { 1731 if (mListeners.register(listener)) { 1732 addDeathRecipient(listener); 1733 } 1734 } 1735 } 1736 addToggleListener(ISensorPrivacyListener listener)1737 public void addToggleListener(ISensorPrivacyListener listener) { 1738 synchronized (mListenerLock) { 1739 if (mToggleSensorListeners.register(listener)) { 1740 addDeathRecipient(listener); 1741 } 1742 } 1743 } 1744 removeListener(ISensorPrivacyListener listener)1745 public void removeListener(ISensorPrivacyListener listener) { 1746 synchronized (mListenerLock) { 1747 if (mListeners.unregister(listener)) { 1748 removeDeathRecipient(listener); 1749 } 1750 } 1751 } 1752 removeToggleListener(ISensorPrivacyListener listener)1753 public void removeToggleListener(ISensorPrivacyListener listener) { 1754 synchronized (mListenerLock) { 1755 if (mToggleSensorListeners.unregister(listener)) { 1756 removeDeathRecipient(listener); 1757 } 1758 } 1759 } 1760 handleSensorPrivacyChanged(boolean enabled)1761 public void handleSensorPrivacyChanged(boolean enabled) { 1762 final int count = mListeners.beginBroadcast(); 1763 for (int i = 0; i < count; i++) { 1764 ISensorPrivacyListener listener = mListeners.getBroadcastItem(i); 1765 try { 1766 listener.onSensorPrivacyChanged(-1, -1, enabled); 1767 } catch (RemoteException e) { 1768 Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e); 1769 } 1770 } 1771 mListeners.finishBroadcast(); 1772 } 1773 handleSensorPrivacyChanged(int userId, int toggleType, int sensor, boolean enabled)1774 public void handleSensorPrivacyChanged(int userId, int toggleType, int sensor, 1775 boolean enabled) { 1776 mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled); 1777 1778 if (userId == mCurrentUser) { 1779 mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, 1780 mSensorPrivacyServiceImpl.isCombinedToggleSensorPrivacyEnabled(sensor)); 1781 } 1782 1783 if (userId != mCurrentUser) { 1784 return; 1785 } 1786 synchronized (mListenerLock) { 1787 try { 1788 final int count = mToggleSensorListeners.beginBroadcast(); 1789 for (int i = 0; i < count; i++) { 1790 ISensorPrivacyListener listener = mToggleSensorListeners.getBroadcastItem( 1791 i); 1792 try { 1793 listener.onSensorPrivacyChanged(toggleType, sensor, enabled); 1794 } catch (RemoteException e) { 1795 Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", 1796 e); 1797 } 1798 } 1799 } finally { 1800 mToggleSensorListeners.finishBroadcast(); 1801 } 1802 } 1803 1804 mSensorPrivacyServiceImpl.showSensorStateChangedActivity(sensor, toggleType); 1805 } 1806 1807 @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) handleSensorPrivacyChanged(int userId, int toggleType, int sensor, int state)1808 public void handleSensorPrivacyChanged(int userId, int toggleType, int sensor, 1809 int state) { 1810 if (userId == mCurrentUser) { 1811 mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, 1812 mSensorPrivacyServiceImpl.isCombinedToggleSensorPrivacyEnabled(sensor)); 1813 } 1814 1815 if (userId != mCurrentUser) { 1816 return; 1817 } 1818 synchronized (mListenerLock) { 1819 try { 1820 final int count = mToggleSensorListeners.beginBroadcast(); 1821 for (int i = 0; i < count; i++) { 1822 ISensorPrivacyListener listener = mToggleSensorListeners.getBroadcastItem( 1823 i); 1824 try { 1825 listener.onSensorPrivacyStateChanged(toggleType, sensor, state); 1826 } catch (RemoteException e) { 1827 Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", 1828 e); 1829 } 1830 } 1831 } finally { 1832 mToggleSensorListeners.finishBroadcast(); 1833 } 1834 } 1835 1836 mSensorPrivacyServiceImpl.showSensorStateChangedActivity(sensor, toggleType); 1837 } 1838 removeSuppressPackageReminderToken(Pair<Integer, UserHandle> key, IBinder token)1839 public void removeSuppressPackageReminderToken(Pair<Integer, UserHandle> key, 1840 IBinder token) { 1841 sendMessage(PooledLambda.obtainMessage( 1842 SensorPrivacyServiceImpl::removeSuppressPackageReminderToken, 1843 mSensorPrivacyServiceImpl, key, token)); 1844 } 1845 addDeathRecipient(ISensorPrivacyListener listener)1846 private void addDeathRecipient(ISensorPrivacyListener listener) { 1847 Pair<DeathRecipient, Integer> deathRecipient = mDeathRecipients.get(listener); 1848 if (deathRecipient == null) { 1849 deathRecipient = new Pair<>(new DeathRecipient(listener), 1); 1850 } else { 1851 int newRefCount = deathRecipient.second + 1; 1852 deathRecipient = new Pair<>(deathRecipient.first, newRefCount); 1853 } 1854 mDeathRecipients.put(listener, deathRecipient); 1855 } 1856 removeDeathRecipient(ISensorPrivacyListener listener)1857 private void removeDeathRecipient(ISensorPrivacyListener listener) { 1858 Pair<DeathRecipient, Integer> deathRecipient = mDeathRecipients.get(listener); 1859 if (deathRecipient == null) { 1860 return; 1861 } else { 1862 int newRefCount = deathRecipient.second - 1; 1863 if (newRefCount == 0) { 1864 mDeathRecipients.remove(listener); 1865 deathRecipient.first.destroy(); 1866 return; 1867 } 1868 deathRecipient = new Pair<>(deathRecipient.first, newRefCount); 1869 } 1870 mDeathRecipients.put(listener, deathRecipient); 1871 } 1872 } 1873 1874 private final class DeathRecipient implements IBinder.DeathRecipient { 1875 1876 private ISensorPrivacyListener mListener; 1877 DeathRecipient(ISensorPrivacyListener listener)1878 DeathRecipient(ISensorPrivacyListener listener) { 1879 mListener = listener; 1880 try { 1881 mListener.asBinder().linkToDeath(this, 0); 1882 } catch (RemoteException e) { 1883 } 1884 } 1885 1886 @Override binderDied()1887 public void binderDied() { 1888 mSensorPrivacyServiceImpl.removeSensorPrivacyListener(mListener); 1889 mSensorPrivacyServiceImpl.removeToggleSensorPrivacyListener(mListener); 1890 } 1891 destroy()1892 public void destroy() { 1893 try { 1894 mListener.asBinder().unlinkToDeath(this, 0); 1895 } catch (NoSuchElementException e) { 1896 } 1897 } 1898 } 1899 forAllUsers(FunctionalUtils.ThrowingConsumer<Integer> c)1900 private void forAllUsers(FunctionalUtils.ThrowingConsumer<Integer> c) { 1901 int[] userIds = mUserManagerInternal.getUserIds(); 1902 for (int i = 0; i < userIds.length; i++) { 1903 c.accept(userIds[i]); 1904 } 1905 } 1906 1907 private class SensorPrivacyManagerInternalImpl extends SensorPrivacyManagerInternal { 1908 1909 private ArrayMap<Integer, ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>>> 1910 mListeners = new ArrayMap<>(); 1911 private ArrayMap<Integer, ArraySet<OnUserSensorPrivacyChangedListener>> mAllUserListeners = 1912 new ArrayMap<>(); 1913 1914 private final Object mLock = new Object(); 1915 dispatch(int userId, int sensor, boolean enabled)1916 private void dispatch(int userId, int sensor, boolean enabled) { 1917 synchronized (mLock) { 1918 ArraySet<OnUserSensorPrivacyChangedListener> allUserSensorListeners = 1919 mAllUserListeners.get(sensor); 1920 if (allUserSensorListeners != null) { 1921 for (int i = 0; i < allUserSensorListeners.size(); i++) { 1922 OnUserSensorPrivacyChangedListener listener = 1923 allUserSensorListeners.valueAt(i); 1924 BackgroundThread.getHandler().post(() -> 1925 listener.onSensorPrivacyChanged(userId, enabled)); 1926 } 1927 } 1928 1929 ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>> userSensorListeners = 1930 mListeners.get(userId); 1931 if (userSensorListeners != null) { 1932 ArraySet<OnSensorPrivacyChangedListener> sensorListeners = 1933 userSensorListeners.get(sensor); 1934 if (sensorListeners != null) { 1935 for (int i = 0; i < sensorListeners.size(); i++) { 1936 OnSensorPrivacyChangedListener listener = sensorListeners.valueAt(i); 1937 BackgroundThread.getHandler().post(() -> 1938 listener.onSensorPrivacyChanged(enabled)); 1939 } 1940 } 1941 } 1942 } 1943 } 1944 1945 @Override isSensorPrivacyEnabled(int userId, int sensor)1946 public boolean isSensorPrivacyEnabled(int userId, int sensor) { 1947 return SensorPrivacyService.this 1948 .mSensorPrivacyServiceImpl.isToggleSensorPrivacyEnabledInternal(userId, 1949 TOGGLE_TYPE_SOFTWARE, sensor); 1950 } 1951 1952 @Override addSensorPrivacyListener(int userId, int sensor, OnSensorPrivacyChangedListener listener)1953 public void addSensorPrivacyListener(int userId, int sensor, 1954 OnSensorPrivacyChangedListener listener) { 1955 synchronized (mLock) { 1956 ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>> userSensorListeners = 1957 mListeners.get(userId); 1958 if (userSensorListeners == null) { 1959 userSensorListeners = new ArrayMap<>(); 1960 mListeners.put(userId, userSensorListeners); 1961 } 1962 1963 ArraySet<OnSensorPrivacyChangedListener> sensorListeners = 1964 userSensorListeners.get(sensor); 1965 if (sensorListeners == null) { 1966 sensorListeners = new ArraySet<>(); 1967 userSensorListeners.put(sensor, sensorListeners); 1968 } 1969 1970 sensorListeners.add(listener); 1971 } 1972 } 1973 1974 @Override addSensorPrivacyListenerForAllUsers(int sensor, OnUserSensorPrivacyChangedListener listener)1975 public void addSensorPrivacyListenerForAllUsers(int sensor, 1976 OnUserSensorPrivacyChangedListener listener) { 1977 synchronized (mLock) { 1978 ArraySet<OnUserSensorPrivacyChangedListener> sensorListeners = 1979 mAllUserListeners.get(sensor); 1980 if (sensorListeners == null) { 1981 sensorListeners = new ArraySet<>(); 1982 mAllUserListeners.put(sensor, sensorListeners); 1983 } 1984 1985 sensorListeners.add(listener); 1986 } 1987 } 1988 1989 @Override setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable)1990 public void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable) { 1991 final SensorPrivacyServiceImpl sps = 1992 SensorPrivacyService.this.mSensorPrivacyServiceImpl; 1993 1994 // Convert userId to actual user Id. mCurrentUser is USER_NULL if toggle state is set 1995 // before onUserStarting. 1996 userId = (userId == UserHandle.USER_CURRENT ? mCurrentUser : userId); 1997 final int realUserId = (userId == UserHandle.USER_NULL ? mContext.getUserId() : userId); 1998 1999 sps.setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_HARDWARE, realUserId, OTHER, sensor, 2000 enable); 2001 // Also disable the SW toggle when disabling the HW toggle 2002 if (!enable) { 2003 sps.setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, realUserId, OTHER, sensor, 2004 enable); 2005 } 2006 } 2007 } 2008 2009 private class CallStateHelper { 2010 private final OutgoingEmergencyStateCallback mEmergencyStateCallback; 2011 private final CallStateCallback mCallStateCallback; 2012 2013 private boolean mIsInEmergencyCall; 2014 private boolean mMicUnmutedForEmergencyCall; 2015 2016 private Object mCallStateLock = new Object(); 2017 CallStateHelper()2018 CallStateHelper() { 2019 mEmergencyStateCallback = new OutgoingEmergencyStateCallback(); 2020 mCallStateCallback = new CallStateCallback(); 2021 2022 mTelephonyManager.registerTelephonyCallback(FgThread.getExecutor(), 2023 mEmergencyStateCallback); 2024 mTelephonyManager.registerTelephonyCallback(FgThread.getExecutor(), 2025 mCallStateCallback); 2026 } 2027 isInEmergencyCall()2028 boolean isInEmergencyCall() { 2029 synchronized (mCallStateLock) { 2030 return mIsInEmergencyCall; 2031 } 2032 } 2033 2034 private class OutgoingEmergencyStateCallback extends TelephonyCallback implements 2035 TelephonyCallback.OutgoingEmergencyCallListener { 2036 @Override onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber, int subscriptionId)2037 public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber, 2038 int subscriptionId) { 2039 onEmergencyCall(); 2040 } 2041 } 2042 2043 private class CallStateCallback extends TelephonyCallback implements 2044 TelephonyCallback.CallStateListener { 2045 @Override onCallStateChanged(int state)2046 public void onCallStateChanged(int state) { 2047 if (state == TelephonyManager.CALL_STATE_IDLE) { 2048 onCallOver(); 2049 } else { 2050 onCall(); 2051 } 2052 } 2053 } 2054 onEmergencyCall()2055 private void onEmergencyCall() { 2056 synchronized (mCallStateLock) { 2057 if (!mIsInEmergencyCall) { 2058 mIsInEmergencyCall = true; 2059 if (mSensorPrivacyServiceImpl 2060 .isToggleSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, MICROPHONE)) { 2061 mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked( 2062 TOGGLE_TYPE_SOFTWARE, mCurrentUser, OTHER, MICROPHONE, false); 2063 mMicUnmutedForEmergencyCall = true; 2064 } else { 2065 mMicUnmutedForEmergencyCall = false; 2066 } 2067 } 2068 } 2069 } 2070 onCall()2071 private void onCall() { 2072 long token = Binder.clearCallingIdentity(); 2073 try { 2074 synchronized (mCallStateLock) { 2075 mSensorPrivacyServiceImpl.showSensorUseDialog(MICROPHONE); 2076 } 2077 } finally { 2078 Binder.restoreCallingIdentity(token); 2079 } 2080 } 2081 onCallOver()2082 private void onCallOver() { 2083 synchronized (mCallStateLock) { 2084 if (mIsInEmergencyCall) { 2085 mIsInEmergencyCall = false; 2086 if (mMicUnmutedForEmergencyCall) { 2087 mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked( 2088 TOGGLE_TYPE_SOFTWARE, mCurrentUser, OTHER, MICROPHONE, true); 2089 mMicUnmutedForEmergencyCall = false; 2090 } 2091 } 2092 } 2093 } 2094 } 2095 getCurrentTimeMillis()2096 static long getCurrentTimeMillis() { 2097 return SystemClock.elapsedRealtime(); 2098 } 2099 } 2100