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