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