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