1 /* 2 * Copyright (C) 2019 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 android.app.role; 18 19 import android.Manifest; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.NonNull; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemService; 24 import android.annotation.TestApi; 25 import android.app.ActivityThread; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageManager; 30 import android.content.pm.ResolveInfo; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.RemoteCallback; 35 import android.util.Log; 36 import android.util.SparseArray; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.internal.infra.AndroidFuture; 40 import com.android.internal.infra.ServiceConnector; 41 42 import java.util.concurrent.Executor; 43 import java.util.concurrent.TimeUnit; 44 import java.util.function.Consumer; 45 46 /** 47 * Interface for communicating with the role controller. 48 * 49 * @hide 50 */ 51 @SystemService(Context.ROLE_CONTROLLER_SERVICE) 52 @TestApi 53 public class RoleControllerManager { 54 55 private static final String LOG_TAG = RoleControllerManager.class.getSimpleName(); 56 57 private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000; 58 59 private static volatile ComponentName sRemoteServiceComponentName; 60 61 private static final Object sRemoteServicesLock = new Object(); 62 63 /** 64 * Global remote services (per user) used by all {@link RoleControllerManager managers}. 65 */ 66 @GuardedBy("sRemoteServicesLock") 67 private static final SparseArray<ServiceConnector<IRoleController>> sRemoteServices = 68 new SparseArray<>(); 69 70 @NonNull 71 private final ServiceConnector<IRoleController> mRemoteService; 72 73 /** 74 * Initialize the remote service component name once so that we can avoid acquiring the 75 * PackageManagerService lock in constructor. 76 * 77 * @see #createWithInitializedRemoteServiceComponentName(Handler, Context) 78 * 79 * @hide 80 */ initializeRemoteServiceComponentName(@onNull Context context)81 public static void initializeRemoteServiceComponentName(@NonNull Context context) { 82 sRemoteServiceComponentName = getRemoteServiceComponentName(context); 83 } 84 85 /** 86 * Create a {@link RoleControllerManager} instance with the initialized remote service component 87 * name so that we can avoid acquiring the PackageManagerService lock in constructor. 88 * 89 * @see #initializeRemoteServiceComponentName(Context) 90 * 91 * @hide 92 */ 93 @NonNull createWithInitializedRemoteServiceComponentName( @onNull Handler handler, @NonNull Context context)94 public static RoleControllerManager createWithInitializedRemoteServiceComponentName( 95 @NonNull Handler handler, @NonNull Context context) { 96 return new RoleControllerManager(sRemoteServiceComponentName, handler, context); 97 } 98 RoleControllerManager(@onNull ComponentName remoteServiceComponentName, @NonNull Handler handler, @NonNull Context context)99 private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName, 100 @NonNull Handler handler, @NonNull Context context) { 101 synchronized (sRemoteServicesLock) { 102 int userId = context.getUserId(); 103 ServiceConnector<IRoleController> remoteService = sRemoteServices.get(userId); 104 if (remoteService == null) { 105 remoteService = new ServiceConnector.Impl<IRoleController>( 106 ActivityThread.currentApplication(), 107 new Intent(RoleControllerService.SERVICE_INTERFACE) 108 .setComponent(remoteServiceComponentName), 109 0 /* bindingFlags */, userId, IRoleController.Stub::asInterface) { 110 111 @Override 112 protected Handler getJobHandler() { 113 return handler; 114 } 115 }; 116 sRemoteServices.put(userId, remoteService); 117 } 118 mRemoteService = remoteService; 119 } 120 } 121 122 /** 123 * @hide 124 */ RoleControllerManager(@onNull Context context)125 public RoleControllerManager(@NonNull Context context) { 126 this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context); 127 } 128 129 @NonNull getRemoteServiceComponentName(@onNull Context context)130 private static ComponentName getRemoteServiceComponentName(@NonNull Context context) { 131 Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE); 132 PackageManager packageManager = context.getPackageManager(); 133 intent.setPackage(packageManager.getPermissionControllerPackageName()); 134 ResolveInfo resolveInfo = packageManager.resolveService(intent, 0); 135 return resolveInfo.getComponentInfo().getComponentName(); 136 } 137 138 /** 139 * @see RoleControllerService#onGrantDefaultRoles() 140 * 141 * @hide 142 */ grantDefaultRoles(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)143 public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor, 144 @NonNull Consumer<Boolean> callback) { 145 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 146 AndroidFuture<Bundle> future = new AndroidFuture<>(); 147 service.grantDefaultRoles(new RemoteCallback(future::complete)); 148 return future; 149 }); 150 propagateCallback(operation, "grantDefaultRoles", executor, callback); 151 } 152 153 /** 154 * @see RoleControllerService#onAddRoleHolder(String, String, int) 155 * 156 * @hide 157 */ onAddRoleHolder(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)158 public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, 159 @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) { 160 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 161 AndroidFuture<Bundle> future = new AndroidFuture<>(); 162 service.onAddRoleHolder(roleName, packageName, flags, 163 new RemoteCallback(future::complete)); 164 return future; 165 }); 166 propagateCallback(operation, "onAddRoleHolder", callback); 167 } 168 169 /** 170 * @see RoleControllerService#onRemoveRoleHolder(String, String, int) 171 * 172 * @hide 173 */ onRemoveRoleHolder(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)174 public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, 175 @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) { 176 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 177 AndroidFuture<Bundle> future = new AndroidFuture<>(); 178 service.onRemoveRoleHolder(roleName, packageName, flags, 179 new RemoteCallback(future::complete)); 180 return future; 181 }); 182 propagateCallback(operation, "onRemoveRoleHolder", callback); 183 } 184 185 /** 186 * @see RoleControllerService#onClearRoleHolders(String, int) 187 * 188 * @hide 189 */ onClearRoleHolders(@onNull String roleName, @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback)190 public void onClearRoleHolders(@NonNull String roleName, 191 @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) { 192 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 193 AndroidFuture<Bundle> future = new AndroidFuture<>(); 194 service.onClearRoleHolders(roleName, flags, 195 new RemoteCallback(future::complete)); 196 return future; 197 }); 198 propagateCallback(operation, "onClearRoleHolders", callback); 199 } 200 201 /** 202 * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String) 203 * 204 * @deprecated Use {@link #isApplicationVisibleForRole(String, String, Executor, Consumer)} 205 * instead. 206 * 207 * @hide 208 */ 209 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) isApplicationQualifiedForRole(@onNull String roleName, @NonNull String packageName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)210 public void isApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName, 211 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 212 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 213 AndroidFuture<Bundle> future = new AndroidFuture<>(); 214 service.isApplicationQualifiedForRole(roleName, packageName, 215 new RemoteCallback(future::complete)); 216 return future; 217 }); 218 propagateCallback(operation, "isApplicationQualifiedForRole", executor, callback); 219 } 220 221 /** 222 * @see RoleControllerService#onIsApplicationVisibleForRole(String, String) 223 * 224 * @hide 225 */ 226 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 227 @TestApi isApplicationVisibleForRole(@onNull String roleName, @NonNull String packageName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)228 public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName, 229 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 230 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 231 AndroidFuture<Bundle> future = new AndroidFuture<>(); 232 service.isApplicationVisibleForRole(roleName, packageName, 233 new RemoteCallback(future::complete)); 234 return future; 235 }); 236 propagateCallback(operation, "isApplicationVisibleForRole", executor, callback); 237 } 238 239 /** 240 * @see RoleControllerService#onIsRoleVisible(String) 241 * 242 * @hide 243 */ 244 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 245 @TestApi isRoleVisible(@onNull String roleName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)246 public void isRoleVisible(@NonNull String roleName, 247 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 248 AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> { 249 AndroidFuture<Bundle> future = new AndroidFuture<>(); 250 service.isRoleVisible(roleName, new RemoteCallback(future::complete)); 251 return future; 252 }); 253 propagateCallback(operation, "isRoleVisible", executor, callback); 254 } 255 propagateCallback(AndroidFuture<Bundle> operation, String opName, @CallbackExecutor @NonNull Executor executor, Consumer<Boolean> destination)256 private void propagateCallback(AndroidFuture<Bundle> operation, String opName, 257 @CallbackExecutor @NonNull Executor executor, 258 Consumer<Boolean> destination) { 259 operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) 260 .whenComplete((res, err) -> executor.execute(() -> { 261 long token = Binder.clearCallingIdentity(); 262 try { 263 if (err != null) { 264 Log.e(LOG_TAG, "Error calling " + opName + "()", err); 265 destination.accept(false); 266 } else { 267 destination.accept(res != null); 268 } 269 } finally { 270 Binder.restoreCallingIdentity(token); 271 } 272 })); 273 } 274 propagateCallback(AndroidFuture<Bundle> operation, String opName, RemoteCallback destination)275 private void propagateCallback(AndroidFuture<Bundle> operation, String opName, 276 RemoteCallback destination) { 277 operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) 278 .whenComplete((res, err) -> { 279 long token = Binder.clearCallingIdentity(); 280 try { 281 if (err != null) { 282 Log.e(LOG_TAG, "Error calling " + opName + "()", err); 283 destination.sendResult(null); 284 } else { 285 destination.sendResult(res); 286 } 287 } finally { 288 Binder.restoreCallingIdentity(token); 289 } 290 }); 291 } 292 } 293