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