blob: cc3064efae6a1144eb2f5cdffdb383789afa5023 [file] [log] [blame]
Hai Zhangb7776682018-09-25 15:10:57 -07001/*
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
17package com.android.server.role;
18
Hai Zhangb7776682018-09-25 15:10:57 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.UserIdInt;
Eugene Suslaa4200f822018-11-09 18:06:43 -080022import android.annotation.WorkerThread;
Hai Zhangb7776682018-09-25 15:10:57 -070023import android.app.role.IRoleManagerCallback;
24import android.app.role.RoleManagerCallback;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.ServiceConnection;
29import android.os.Handler;
30import android.os.IBinder;
Hai Zhang527dd512018-10-19 11:41:33 -070031import android.os.RemoteException;
Hai Zhangb7776682018-09-25 15:10:57 -070032import android.os.UserHandle;
33import android.rolecontrollerservice.IRoleControllerService;
34import android.rolecontrollerservice.RoleControllerService;
35import android.util.Slog;
36
Hai Zhangb7776682018-09-25 15:10:57 -070037import com.android.internal.util.function.pooled.PooledLambda;
Hai Zhangfcbc3382018-12-06 15:34:05 -080038import com.android.server.FgThread;
Hai Zhangb7776682018-09-25 15:10:57 -070039
40import java.util.ArrayDeque;
41import java.util.Queue;
42
43/**
44 * Handles connection with {@link RoleControllerService}.
45 */
46public class RemoteRoleControllerService {
47
Eugene Suslaa4200f822018-11-09 18:06:43 -080048 static final boolean DEBUG = false;
Hai Zhangb7776682018-09-25 15:10:57 -070049 private static final String LOG_TAG = RemoteRoleControllerService.class.getSimpleName();
50
Eugene Suslaa4200f822018-11-09 18:06:43 -080051 @NonNull
Hai Zhangb7776682018-09-25 15:10:57 -070052 private final Connection mConnection;
53
54 public RemoteRoleControllerService(@UserIdInt int userId, @NonNull Context context) {
55 mConnection = new Connection(userId, context);
56 }
57
58 /**
59 * Add a specific application to the holders of a role. If the role is exclusive, the previous
60 * holder will be replaced.
61 *
62 * @see RoleControllerService#onAddRoleHolder(String, String, RoleManagerCallback)
63 */
64 public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
65 @NonNull IRoleManagerCallback callback) {
Hai Zhang527dd512018-10-19 11:41:33 -070066 mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
67 service.onAddRoleHolder(roleName, packageName, callbackDelegate), callback));
Hai Zhangb7776682018-09-25 15:10:57 -070068 }
69
70 /**
71 * Remove a specific application from the holders of a role.
72 *
73 * @see RoleControllerService#onRemoveRoleHolder(String, String, RoleManagerCallback)
74 */
75 public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
76 @NonNull IRoleManagerCallback callback) {
Hai Zhang527dd512018-10-19 11:41:33 -070077 mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
78 service.onRemoveRoleHolder(roleName, packageName, callbackDelegate), callback));
Hai Zhangb7776682018-09-25 15:10:57 -070079 }
80
81 /**
82 * Remove all holders of a role.
83 *
84 * @see RoleControllerService#onClearRoleHolders(String, RoleManagerCallback)
85 */
86 public void onClearRoleHolders(@NonNull String roleName,
87 @NonNull IRoleManagerCallback callback) {
Hai Zhang527dd512018-10-19 11:41:33 -070088 mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
89 service.onClearRoleHolders(roleName, callbackDelegate), callback));
Hai Zhangb7776682018-09-25 15:10:57 -070090 }
91
Eugene Suslaa4200f822018-11-09 18:06:43 -080092 /**
93 * Performs granting of default roles and permissions and appops
94 *
95 * @see RoleControllerService#onGrantDefaultRoles(RoleManagerCallback)
96 */
97 public void onGrantDefaultRoles(@NonNull IRoleManagerCallback callback) {
Hai Zhangfcbc3382018-12-06 15:34:05 -080098 mConnection.enqueueCall(new Connection.Call(IRoleControllerService::onGrantDefaultRoles,
99 callback));
Eugene Suslaa4200f822018-11-09 18:06:43 -0800100 }
101
Hai Zhangb7776682018-09-25 15:10:57 -0700102 private static final class Connection implements ServiceConnection {
103
Hai Zhang527dd512018-10-19 11:41:33 -0700104 private static final long UNBIND_DELAY_MILLIS = 15 * 1000;
Hai Zhangb7776682018-09-25 15:10:57 -0700105
106 @UserIdInt
107 private final int mUserId;
108
109 @NonNull
110 private final Context mContext;
111
Hai Zhangfcbc3382018-12-06 15:34:05 -0800112 @NonNull
113 private final Handler mHandler = FgThread.getHandler();
114
Hai Zhangb7776682018-09-25 15:10:57 -0700115 private boolean mBound;
116
117 @Nullable
118 private IRoleControllerService mService;
119
120 @NonNull
121 private final Queue<Call> mPendingCalls = new ArrayDeque<>();
122
123 @NonNull
124 private final Runnable mUnbindRunnable = this::unbind;
125
126 Connection(@UserIdInt int userId, @NonNull Context context) {
127 mUserId = userId;
128 mContext = context;
129 }
130
Hai Zhangb7776682018-09-25 15:10:57 -0700131 @Override
Eugene Suslaa4200f822018-11-09 18:06:43 -0800132 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700133 public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) {
134 mService = IRoleControllerService.Stub.asInterface(service);
135 executePendingCalls();
136 }
137
Eugene Suslaa4200f822018-11-09 18:06:43 -0800138 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700139 private void executePendingCalls() {
140 while (!mPendingCalls.isEmpty()) {
141 Call call = mPendingCalls.poll();
142 call.execute(mService);
143 }
144 scheduleUnbind();
145 }
146
Hai Zhangb7776682018-09-25 15:10:57 -0700147 @Override
Eugene Suslaa4200f822018-11-09 18:06:43 -0800148 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700149 public void onServiceDisconnected(@NonNull ComponentName name) {
150 mService = null;
151 }
152
Hai Zhangb7776682018-09-25 15:10:57 -0700153 @Override
Eugene Suslaa4200f822018-11-09 18:06:43 -0800154 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700155 public void onBindingDied(@NonNull ComponentName name) {
156 unbind();
157 }
158
159 public void enqueueCall(@NonNull Call call) {
Eugene Suslaa4200f822018-11-09 18:06:43 -0800160 if (DEBUG) {
161 Slog.i(LOG_TAG, "Enqueue " + call);
162 }
Hai Zhangfcbc3382018-12-06 15:34:05 -0800163 mHandler.executeOrSendMessage(PooledLambda.obtainMessage(Connection::executeCall, this,
164 call));
Hai Zhangb7776682018-09-25 15:10:57 -0700165 }
166
Eugene Suslaa4200f822018-11-09 18:06:43 -0800167 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700168 private void executeCall(@NonNull Call call) {
169 ensureBound();
170 if (mService == null) {
Eugene Suslaa4200f822018-11-09 18:06:43 -0800171 if (DEBUG) {
172 Slog.i(LOG_TAG, "Delaying until service connected: " + call);
173 }
Hai Zhangb7776682018-09-25 15:10:57 -0700174 mPendingCalls.offer(call);
175 return;
176 }
177 call.execute(mService);
178 scheduleUnbind();
179 }
180
Eugene Suslaa4200f822018-11-09 18:06:43 -0800181 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700182 private void ensureBound() {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800183 mHandler.removeCallbacks(mUnbindRunnable);
Hai Zhangb7776682018-09-25 15:10:57 -0700184 if (!mBound) {
185 Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
186 intent.setPackage(mContext.getPackageManager()
187 .getPermissionControllerPackageName());
Eugene Suslaa4200f822018-11-09 18:06:43 -0800188 // Use direct handler to ensure onServiceConnected callback happens in the same
189 // call frame, as required by onGrantDefaultRoles
190 //
191 // Note that as a result, onServiceConnected may happen not on main thread!
Hai Zhangb7776682018-09-25 15:10:57 -0700192 mBound = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Hai Zhangfcbc3382018-12-06 15:34:05 -0800193 mHandler, UserHandle.of(mUserId));
Hai Zhangb7776682018-09-25 15:10:57 -0700194 }
195 }
196
197 private void scheduleUnbind() {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800198 mHandler.removeCallbacks(mUnbindRunnable);
199 mHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS);
Hai Zhangb7776682018-09-25 15:10:57 -0700200 }
201
Eugene Suslaa4200f822018-11-09 18:06:43 -0800202 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700203 private void unbind() {
204 if (mBound) {
205 mService = null;
206 mContext.unbindService(this);
207 mBound = false;
208 }
209 }
210
211 public static class Call {
212
Hai Zhang527dd512018-10-19 11:41:33 -0700213 private static final int TIMEOUT_MILLIS = 15 * 1000;
Hai Zhangb7776682018-09-25 15:10:57 -0700214
215 @NonNull
Hai Zhang527dd512018-10-19 11:41:33 -0700216 private final CallExecutor mCallExecutor;
Hai Zhangb7776682018-09-25 15:10:57 -0700217
Hai Zhang527dd512018-10-19 11:41:33 -0700218 @NonNull
219 private final IRoleManagerCallback mCallback;
220
221 @NonNull
Hai Zhangfcbc3382018-12-06 15:34:05 -0800222 private final Handler mHandler = FgThread.getHandler();
223
224 @NonNull
Hai Zhangb295ac42018-11-16 16:08:18 -0800225 private final Runnable mTimeoutRunnable = this::notifyTimeout;
Hai Zhang527dd512018-10-19 11:41:33 -0700226
227 private boolean mCallbackNotified;
228
229 private Call(@NonNull CallExecutor callExecutor,
230 @NonNull IRoleManagerCallback callback) {
231 mCallExecutor = callExecutor;
232 mCallback = callback;
Hai Zhangb7776682018-09-25 15:10:57 -0700233 }
234
Eugene Suslaa4200f822018-11-09 18:06:43 -0800235 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700236 public void execute(IRoleControllerService service) {
Eugene Suslaa4200f822018-11-09 18:06:43 -0800237 if (DEBUG) {
238 Slog.i(LOG_TAG, "Executing " + this);
239 }
Hai Zhangb7776682018-09-25 15:10:57 -0700240 try {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800241 mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MILLIS);
Hai Zhang527dd512018-10-19 11:41:33 -0700242 mCallExecutor.execute(service, new CallbackDelegate());
243 } catch (RemoteException e) {
244 Slog.e(LOG_TAG, "Error calling RoleControllerService", e);
245 notifyCallback(false);
246 }
247 }
248
Eugene Suslaa4200f822018-11-09 18:06:43 -0800249 @WorkerThread
Hai Zhangb295ac42018-11-16 16:08:18 -0800250 private void notifyTimeout() {
251 Slog.e(LOG_TAG, "Call timed out, calling onFailure()");
252 notifyCallback(false);
253 }
254
255 @WorkerThread
Hai Zhang527dd512018-10-19 11:41:33 -0700256 private void notifyCallback(boolean success) {
257 if (mCallbackNotified) {
258 return;
259 }
260 mCallbackNotified = true;
Hai Zhangfcbc3382018-12-06 15:34:05 -0800261 mHandler.removeCallbacks(mTimeoutRunnable);
Hai Zhang527dd512018-10-19 11:41:33 -0700262 try {
263 if (success) {
264 mCallback.onSuccess();
265 } else {
266 mCallback.onFailure();
Hai Zhangb7776682018-09-25 15:10:57 -0700267 }
Hai Zhang527dd512018-10-19 11:41:33 -0700268 } catch (RemoteException e) {
269 Slog.e(LOG_TAG, "Error calling " + (success ? "onSuccess()" : "onFailure()")
270 + " callback", e);
271 }
272 }
273
Eugene Suslaa4200f822018-11-09 18:06:43 -0800274 @Override
275 public String toString() {
276 return "Call with callback: " + mCallback;
277 }
278
Hai Zhang527dd512018-10-19 11:41:33 -0700279 @FunctionalInterface
280 public interface CallExecutor {
281
Eugene Suslaa4200f822018-11-09 18:06:43 -0800282 @WorkerThread
Hai Zhang527dd512018-10-19 11:41:33 -0700283 void execute(IRoleControllerService service, IRoleManagerCallback callbackDelegate)
284 throws RemoteException;
285 }
286
287 private class CallbackDelegate extends IRoleManagerCallback.Stub {
288
289 @Override
290 public void onSuccess() throws RemoteException {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800291 mHandler.sendMessage(PooledLambda.obtainMessage(Call::notifyCallback, Call.this,
292 true));
Hai Zhang527dd512018-10-19 11:41:33 -0700293 }
294
295 @Override
296 public void onFailure() throws RemoteException {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800297 mHandler.sendMessage(PooledLambda.obtainMessage(Call::notifyCallback, Call.this,
298 false));
Hai Zhangb7776682018-09-25 15:10:57 -0700299 }
300 }
301 }
302 }
303}