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