blob: 2313d5972cbd807a14c53a7b389d19686bec264e [file] [log] [blame]
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -08001/*
2 * Copyright (C) 2016 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
17package android.permission;
18
Philip P. Moltmann41df9f92019-02-08 13:07:57 -080019import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
20import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
21import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
Philip P. Moltmanne1436e852019-01-31 14:22:39 -080022import static android.permission.PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED;
23import static android.permission.PermissionControllerManager.COUNT_WHEN_SYSTEM;
24
Philip P. Moltmann78689522018-12-17 20:45:40 -080025import static com.android.internal.util.Preconditions.checkArgument;
Joel Galenson5f63b832018-12-19 15:38:04 -080026import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -080027import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
Philip P. Moltmanne1436e852019-01-31 14:22:39 -080028import static com.android.internal.util.Preconditions.checkFlagsArgument;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080029import static com.android.internal.util.Preconditions.checkNotNull;
Hai Zhang19821872019-01-23 16:48:40 -080030import static com.android.internal.util.Preconditions.checkStringNotEmpty;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080031import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
32
Philip P. Moltmannbc054d82018-12-21 09:41:58 -080033import android.Manifest;
Philip P. Moltmann7532c612019-01-20 09:01:19 -080034import android.annotation.BinderThread;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080035import android.annotation.NonNull;
36import android.annotation.SystemApi;
37import android.app.Service;
Philip P. Moltmann41df9f92019-02-08 13:07:57 -080038import android.app.admin.DevicePolicyManager.PermissionGrantState;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080039import android.content.Context;
40import android.content.Intent;
Philip P. Moltmann78689522018-12-17 20:45:40 -080041import android.content.pm.PackageInfo;
42import android.content.pm.PackageManager;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080043import android.os.Bundle;
44import android.os.Handler;
45import android.os.IBinder;
Philip P. Moltmann97142e22019-01-10 17:03:42 -080046import android.os.ParcelFileDescriptor;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080047import android.os.RemoteCallback;
Philip P. Moltmann97142e22019-01-10 17:03:42 -080048import android.os.UserHandle;
Philip P. Moltmanne1436e852019-01-31 14:22:39 -080049import android.permission.PermissionControllerManager.CountPermissionAppsFlag;
Philip P. Moltmann78689522018-12-17 20:45:40 -080050import android.util.ArrayMap;
Philip P. Moltmann97142e22019-01-10 17:03:42 -080051import android.util.Log;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080052
Philip P. Moltmann78689522018-12-17 20:45:40 -080053import com.android.internal.util.Preconditions;
54
Philip P. Moltmann97142e22019-01-10 17:03:42 -080055import java.io.IOException;
Philip P. Moltmann7532c612019-01-20 09:01:19 -080056import java.io.InputStream;
Philip P. Moltmann97142e22019-01-10 17:03:42 -080057import java.io.OutputStream;
Philip P. Moltmann78689522018-12-17 20:45:40 -080058import java.util.ArrayList;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080059import java.util.List;
Philip P. Moltmann78689522018-12-17 20:45:40 -080060import java.util.Map;
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080061
62/**
Philip P. Moltmannbc054d82018-12-21 09:41:58 -080063 * This service is meant to be implemented by the app controlling permissions.
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080064 *
Philip P. Moltmann9b12e372019-01-20 09:01:19 -080065 * @see PermissionControllerManager
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080066 *
67 * @hide
68 */
69@SystemApi
Philip P. Moltmannbc054d82018-12-21 09:41:58 -080070public abstract class PermissionControllerService extends Service {
Philip P. Moltmann97142e22019-01-10 17:03:42 -080071 private static final String LOG_TAG = PermissionControllerService.class.getSimpleName();
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080072
73 /**
74 * The {@link Intent} action that must be declared as handled by a service
75 * in its manifest for the system to recognize it as a runtime permission
76 * presenter service.
77 */
Philip P. Moltmannbc054d82018-12-21 09:41:58 -080078 public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -080079
80 // No need for locking - always set first and never modified
81 private Handler mHandler;
82
83 @Override
84 public final void attachBaseContext(Context base) {
85 super.attachBaseContext(base);
86 mHandler = new Handler(base.getMainLooper());
87 }
88
89 /**
Philip P. Moltmann78689522018-12-17 20:45:40 -080090 * Revoke a set of runtime permissions for various apps.
91 *
92 * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>}
93 * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
94 * @param reason Why the permission should be revoked
95 * @param callerPackageName The package name of the calling app
96 *
97 * @return the actually removed permissions as {@code Map<packageName, List<permission>>}
98 */
99 public abstract @NonNull Map<String, List<String>> onRevokeRuntimePermissions(
100 @NonNull Map<String, List<String>> requests, boolean doDryRun,
101 @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName);
102
103 /**
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800104 * Create a backup of the runtime permissions.
105 *
106 * @param user The user to back up
Philip P. Moltmann9b12e372019-01-20 09:01:19 -0800107 * @param backup The stream to write the backup to
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800108 */
109 public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
Philip P. Moltmann9b12e372019-01-20 09:01:19 -0800110 @NonNull OutputStream backup);
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800111
112 /**
Philip P. Moltmann7532c612019-01-20 09:01:19 -0800113 * Restore a backup of the runtime permissions.
114 *
Philip P. Moltmann4198dd12019-03-08 15:42:56 -0800115 * <p>If an app mentioned in the backup is not installed the state should be saved to later
116 * be restored via {@link #onRestoreDelayedRuntimePermissionsBackup}.
117 *
Philip P. Moltmann7532c612019-01-20 09:01:19 -0800118 * @param user The user to restore
119 * @param backup The stream to read the backup from
120 */
121 @BinderThread
122 public abstract void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
123 @NonNull InputStream backup);
124
125 /**
Philip P. Moltmann4198dd12019-03-08 15:42:56 -0800126 * Restore the permission state of an app that was provided in
127 * {@link #onRestoreRuntimePermissionsBackup} but could not be restored back then.
Philip P. Moltmann7532c612019-01-20 09:01:19 -0800128 *
129 * @param packageName The app to restore
130 * @param user The user to restore
131 *
132 * @return {@code true} iff there is still delayed backup left
133 */
134 @BinderThread
135 public abstract boolean onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
136 @NonNull UserHandle user);
137
138 /**
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800139 * Gets the runtime permissions for an app.
140 *
141 * @param packageName The package for which to query.
142 *
143 * @return descriptions of the runtime permissions of the app
144 */
145 public abstract @NonNull List<RuntimePermissionPresentationInfo> onGetAppPermissions(
146 @NonNull String packageName);
147
148 /**
149 * Revokes the permission {@code permissionName} for app {@code packageName}
150 *
151 * @param packageName The package for which to revoke
152 * @param permissionName The permission to revoke
153 */
154 public abstract void onRevokeRuntimePermission(@NonNull String packageName,
155 @NonNull String permissionName);
156
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800157 /**
158 * Count how many apps have one of a set of permissions.
159 *
160 * @param permissionNames The permissions the app might have
Philip P. Moltmanne1436e852019-01-31 14:22:39 -0800161 * @param flags Modify which apps to count. By default all non-system apps that request a
162 * permission are counted
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800163 *
164 * @return the number of apps that have one of the permissions
165 */
166 public abstract int onCountPermissionApps(@NonNull List<String> permissionNames,
Philip P. Moltmanne1436e852019-01-31 14:22:39 -0800167 @CountPermissionAppsFlag int flags);
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800168
Joel Galenson5f63b832018-12-19 15:38:04 -0800169 /**
170 * Count how many apps have used permissions.
171 *
172 * @param countSystem Also count system apps
173 * @param numMillis The number of milliseconds in the past to check for uses
174 *
175 * @return descriptions of the users of permissions
176 */
Hai Zhang19821872019-01-23 16:48:40 -0800177 public abstract @NonNull List<RuntimePermissionUsageInfo> onGetPermissionUsages(
178 boolean countSystem, long numMillis);
179
180 /**
Philip P. Moltmann41df9f92019-02-08 13:07:57 -0800181 * Set the runtime permission state from a device admin.
182 *
183 * @param callerPackageName The package name of the admin requesting the change
184 * @param packageName Package the permission belongs to
185 * @param permission Permission to change
186 * @param grantState State to set the permission into
187 */
188 public abstract boolean onSetRuntimePermissionGrantStateByDeviceAdmin(
189 @NonNull String callerPackageName, @NonNull String packageName,
190 @NonNull String permission, @PermissionGrantState int grantState);
191
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800192 @Override
Philip P. Moltmann051f3382019-03-01 10:49:32 -0800193 public final @NonNull IBinder onBind(Intent intent) {
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800194 return new IPermissionController.Stub() {
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800195 @Override
Philip P. Moltmann78689522018-12-17 20:45:40 -0800196 public void revokeRuntimePermissions(
197 Bundle bundleizedRequest, boolean doDryRun, int reason,
198 String callerPackageName, RemoteCallback callback) {
199 checkNotNull(bundleizedRequest, "bundleizedRequest");
200 checkNotNull(callerPackageName);
201 checkNotNull(callback);
202
203 Map<String, List<String>> request = new ArrayMap<>();
204 for (String packageName : bundleizedRequest.keySet()) {
205 Preconditions.checkNotNull(packageName);
206
207 ArrayList<String> permissions =
208 bundleizedRequest.getStringArrayList(packageName);
209 Preconditions.checkCollectionElementsNotNull(permissions, "permissions");
210
211 request.put(packageName, permissions);
212 }
213
214 enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
215
216 // Verify callerPackageName
217 try {
218 PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0);
219 checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid);
220 } catch (PackageManager.NameNotFoundException e) {
221 throw new RuntimeException(e);
222 }
223
224 mHandler.sendMessage(obtainMessage(
225 PermissionControllerService::revokeRuntimePermissions,
226 PermissionControllerService.this, request, doDryRun, reason,
227 callerPackageName, callback));
228 }
229
230 @Override
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800231 public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
232 checkNotNull(user);
233 checkNotNull(pipe);
234
235 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
236
237 mHandler.sendMessage(obtainMessage(
238 PermissionControllerService::getRuntimePermissionsBackup,
239 PermissionControllerService.this, user, pipe));
240 }
241
242 @Override
Philip P. Moltmann7532c612019-01-20 09:01:19 -0800243 public void restoreRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
244 checkNotNull(user);
245 checkNotNull(pipe);
246
247 enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
248
249 try (InputStream backup = new ParcelFileDescriptor.AutoCloseInputStream(pipe)) {
250 onRestoreRuntimePermissionsBackup(user, backup);
251 } catch (IOException e) {
252 Log.e(LOG_TAG, "Could not open pipe to read backup from", e);
253 }
254 }
255
256 @Override
257 public void restoreDelayedRuntimePermissionBackup(String packageName, UserHandle user,
258 RemoteCallback callback) {
259 checkNotNull(packageName);
260 checkNotNull(user);
261 checkNotNull(callback);
262
263 enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
264
265 boolean hasMoreBackup = onRestoreDelayedRuntimePermissionsBackup(packageName, user);
266
267 Bundle result = new Bundle();
268 result.putBoolean(PermissionControllerManager.KEY_RESULT, hasMoreBackup);
269 callback.sendResult(result);
270 }
271
272 @Override
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800273 public void getAppPermissions(String packageName, RemoteCallback callback) {
274 checkNotNull(packageName, "packageName");
275 checkNotNull(callback, "callback");
276
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800277 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
278
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800279 mHandler.sendMessage(
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800280 obtainMessage(PermissionControllerService::getAppPermissions,
281 PermissionControllerService.this, packageName, callback));
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800282 }
283
284 @Override
285 public void revokeRuntimePermission(String packageName, String permissionName) {
286 checkNotNull(packageName, "packageName");
287 checkNotNull(permissionName, "permissionName");
288
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800289 enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
290
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800291 mHandler.sendMessage(
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800292 obtainMessage(PermissionControllerService::onRevokeRuntimePermission,
293 PermissionControllerService.this, packageName, permissionName));
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800294 }
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800295
296 @Override
Philip P. Moltmanne1436e852019-01-31 14:22:39 -0800297 public void countPermissionApps(List<String> permissionNames, int flags,
298 RemoteCallback callback) {
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800299 checkCollectionElementsNotNull(permissionNames, "permissionNames");
Philip P. Moltmanne1436e852019-01-31 14:22:39 -0800300 checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED);
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800301 checkNotNull(callback, "callback");
302
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800303 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
304
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800305 mHandler.sendMessage(
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800306 obtainMessage(PermissionControllerService::countPermissionApps,
Philip P. Moltmanne1436e852019-01-31 14:22:39 -0800307 PermissionControllerService.this, permissionNames, flags,
308 callback));
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800309 }
Joel Galenson5f63b832018-12-19 15:38:04 -0800310
311 @Override
312 public void getPermissionUsages(boolean countSystem, long numMillis,
313 RemoteCallback callback) {
314 checkArgumentNonnegative(numMillis);
315 checkNotNull(callback, "callback");
316
317 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
318
319 mHandler.sendMessage(
320 obtainMessage(PermissionControllerService::getPermissionUsages,
321 PermissionControllerService.this, countSystem, numMillis,
322 callback));
323 }
Hai Zhang19821872019-01-23 16:48:40 -0800324
325 @Override
Philip P. Moltmann41df9f92019-02-08 13:07:57 -0800326 public void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName,
327 String packageName, String permission, int grantState,
328 RemoteCallback callback) {
329 checkStringNotEmpty(callerPackageName);
330 checkStringNotEmpty(packageName);
331 checkStringNotEmpty(permission);
332 checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED
333 || grantState == PERMISSION_GRANT_STATE_DENIED
334 || grantState == PERMISSION_GRANT_STATE_DEFAULT);
335 checkNotNull(callback);
336
337 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
338 enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
339 }
340
341 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
342 enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
343 }
344
345 enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
346 null);
347
348 mHandler.sendMessage(obtainMessage(
349 PermissionControllerService::setRuntimePermissionGrantStateByDeviceAdmin,
350 PermissionControllerService.this, callerPackageName, packageName,
351 permission, grantState, callback));
352 }
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800353 };
354 }
355
Philip P. Moltmann78689522018-12-17 20:45:40 -0800356 private void revokeRuntimePermissions(@NonNull Map<String, List<String>> requests,
357 boolean doDryRun, @PermissionControllerManager.Reason int reason,
358 @NonNull String callerPackageName, @NonNull RemoteCallback callback) {
359 Map<String, List<String>> revoked = onRevokeRuntimePermissions(requests,
360 doDryRun, reason, callerPackageName);
361
362 checkNotNull(revoked);
363 Bundle bundledizedRevoked = new Bundle();
364 for (Map.Entry<String, List<String>> appRevocation : revoked.entrySet()) {
365 checkNotNull(appRevocation.getKey());
366 checkCollectionElementsNotNull(appRevocation.getValue(), "permissions");
367
368 bundledizedRevoked.putStringArrayList(appRevocation.getKey(),
369 new ArrayList<>(appRevocation.getValue()));
370 }
371
372 Bundle result = new Bundle();
373 result.putBundle(PermissionControllerManager.KEY_RESULT, bundledizedRevoked);
374 callback.sendResult(result);
375 }
376
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800377 private void getRuntimePermissionsBackup(@NonNull UserHandle user,
Philip P. Moltmann9b12e372019-01-20 09:01:19 -0800378 @NonNull ParcelFileDescriptor backupFile) {
379 try (OutputStream backup = new ParcelFileDescriptor.AutoCloseOutputStream(backupFile)) {
380 onGetRuntimePermissionsBackup(user, backup);
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800381 } catch (IOException e) {
Philip P. Moltmann9b12e372019-01-20 09:01:19 -0800382 Log.e(LOG_TAG, "Could not open pipe to write backup to", e);
Philip P. Moltmann97142e22019-01-10 17:03:42 -0800383 }
384 }
385
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800386 private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
387 List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
388 if (permissions != null && !permissions.isEmpty()) {
389 Bundle result = new Bundle();
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800390 result.putParcelableList(PermissionControllerManager.KEY_RESULT, permissions);
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800391 callback.sendResult(result);
392 } else {
393 callback.sendResult(null);
394 }
395 }
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800396
397 private void countPermissionApps(@NonNull List<String> permissionNames,
Philip P. Moltmanne1436e852019-01-31 14:22:39 -0800398 @CountPermissionAppsFlag int flags, @NonNull RemoteCallback callback) {
399 int numApps = onCountPermissionApps(permissionNames, flags);
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800400
401 Bundle result = new Bundle();
Philip P. Moltmannbc054d82018-12-21 09:41:58 -0800402 result.putInt(PermissionControllerManager.KEY_RESULT, numApps);
Philip P. Moltmann08cac8e2018-12-04 15:09:59 -0800403 callback.sendResult(result);
404 }
Joel Galenson5f63b832018-12-19 15:38:04 -0800405
406 private void getPermissionUsages(boolean countSystem, long numMillis,
407 @NonNull RemoteCallback callback) {
408 List<RuntimePermissionUsageInfo> users =
Hai Zhang19821872019-01-23 16:48:40 -0800409 onGetPermissionUsages(countSystem, numMillis);
Joel Galenson5f63b832018-12-19 15:38:04 -0800410 if (users != null && !users.isEmpty()) {
411 Bundle result = new Bundle();
412 result.putParcelableList(PermissionControllerManager.KEY_RESULT, users);
413 callback.sendResult(result);
414 } else {
415 callback.sendResult(null);
416 }
417 }
Hai Zhang19821872019-01-23 16:48:40 -0800418
Philip P. Moltmann41df9f92019-02-08 13:07:57 -0800419 private void setRuntimePermissionGrantStateByDeviceAdmin(@NonNull String callerPackageName,
420 @NonNull String packageName, @NonNull String permission,
421 @PermissionGrantState int grantState, @NonNull RemoteCallback callback) {
422 boolean wasSet = onSetRuntimePermissionGrantStateByDeviceAdmin(callerPackageName,
423 packageName, permission, grantState);
424
425 Bundle result = new Bundle();
426 result.putBoolean(PermissionControllerManager.KEY_RESULT, wasSet);
427 callback.sendResult(result);
428 }
Philip P. Moltmanndbf78b82018-12-04 13:44:27 -0800429}