blob: 4fb40db8597c0bc4f573a3a120fb14508ef55b92 [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;
Hai Zhang71d70362019-02-04 16:17:38 -080024import android.app.role.RoleManager;
Hai Zhangb7776682018-09-25 15:10:57 -070025import android.app.role.RoleManagerCallback;
26import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.content.ServiceConnection;
30import android.os.Handler;
31import android.os.IBinder;
Hai Zhang527dd512018-10-19 11:41:33 -070032import android.os.RemoteException;
Hai Zhangb7776682018-09-25 15:10:57 -070033import android.os.UserHandle;
34import android.rolecontrollerservice.IRoleControllerService;
35import android.rolecontrollerservice.RoleControllerService;
Eugene Susla92b88c72019-01-11 13:31:20 -080036import android.util.Log;
Hai Zhangb7776682018-09-25 15:10:57 -070037import android.util.Slog;
38
Hai Zhangb7776682018-09-25 15:10:57 -070039import com.android.internal.util.function.pooled.PooledLambda;
Hai Zhangfcbc3382018-12-06 15:34:05 -080040import com.android.server.FgThread;
Hai Zhangb7776682018-09-25 15:10:57 -070041
42import java.util.ArrayDeque;
Eugene Susla92b88c72019-01-11 13:31:20 -080043import java.util.Arrays;
Hai Zhangb7776682018-09-25 15:10:57 -070044import java.util.Queue;
45
46/**
47 * Handles connection with {@link RoleControllerService}.
48 */
49public class RemoteRoleControllerService {
50
Eugene Suslaa4200f822018-11-09 18:06:43 -080051 static final boolean DEBUG = false;
Hai Zhangb7776682018-09-25 15:10:57 -070052 private static final String LOG_TAG = RemoteRoleControllerService.class.getSimpleName();
53
Eugene Suslaa4200f822018-11-09 18:06:43 -080054 @NonNull
Hai Zhangb7776682018-09-25 15:10:57 -070055 private final Connection mConnection;
56
57 public RemoteRoleControllerService(@UserIdInt int userId, @NonNull Context context) {
58 mConnection = new Connection(userId, context);
59 }
60
61 /**
62 * Add a specific application to the holders of a role. If the role is exclusive, the previous
63 * holder will be replaced.
64 *
Hai Zhang71d70362019-02-04 16:17:38 -080065 * @see RoleControllerService#onAddRoleHolder(String, String, int, RoleManagerCallback)
Hai Zhangb7776682018-09-25 15:10:57 -070066 */
67 public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
Hai Zhang71d70362019-02-04 16:17:38 -080068 @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
Hai Zhang527dd512018-10-19 11:41:33 -070069 mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
Hai Zhang71d70362019-02-04 16:17:38 -080070 service.onAddRoleHolder(roleName, packageName, flags, callbackDelegate), callback));
Hai Zhangb7776682018-09-25 15:10:57 -070071 }
72
73 /**
74 * Remove a specific application from the holders of a role.
75 *
Hai Zhang71d70362019-02-04 16:17:38 -080076 * @see RoleControllerService#onRemoveRoleHolder(String, String, int, RoleManagerCallback)
Hai Zhangb7776682018-09-25 15:10:57 -070077 */
78 public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
Hai Zhang71d70362019-02-04 16:17:38 -080079 @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
Hai Zhang527dd512018-10-19 11:41:33 -070080 mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
Hai Zhang71d70362019-02-04 16:17:38 -080081 service.onRemoveRoleHolder(roleName, packageName, flags, callbackDelegate),
82 callback));
Hai Zhangb7776682018-09-25 15:10:57 -070083 }
84
85 /**
86 * Remove all holders of a role.
87 *
Hai Zhang71d70362019-02-04 16:17:38 -080088 * @see RoleControllerService#onClearRoleHolders(String, int, RoleManagerCallback)
Hai Zhangb7776682018-09-25 15:10:57 -070089 */
90 public void onClearRoleHolders(@NonNull String roleName,
Hai Zhang71d70362019-02-04 16:17:38 -080091 @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
Hai Zhang527dd512018-10-19 11:41:33 -070092 mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
Hai Zhang71d70362019-02-04 16:17:38 -080093 service.onClearRoleHolders(roleName, flags, callbackDelegate), callback));
Hai Zhangb7776682018-09-25 15:10:57 -070094 }
95
Eugene Suslaa4200f822018-11-09 18:06:43 -080096 /**
97 * Performs granting of default roles and permissions and appops
98 *
99 * @see RoleControllerService#onGrantDefaultRoles(RoleManagerCallback)
100 */
101 public void onGrantDefaultRoles(@NonNull IRoleManagerCallback callback) {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800102 mConnection.enqueueCall(new Connection.Call(IRoleControllerService::onGrantDefaultRoles,
103 callback));
Eugene Suslaa4200f822018-11-09 18:06:43 -0800104 }
105
Eugene Susla34969062019-01-29 11:02:02 -0800106 /**
107 * @see RoleControllerService#onSmsKillSwitchToggled(boolean)
108 */
109 public void onSmsKillSwitchToggled(boolean smsRestrictionEnabled) {
110 mConnection.enqueueCall(new Connection.Call(
111 (s, cb) -> s.onSmsKillSwitchToggled(smsRestrictionEnabled),
112 new IRoleManagerCallback.Default() {
113 @Override
114 public void onFailure() {
115 Slog.e(LOG_TAG, "Failed onSmsKillSwitchToggled");
116 }
117 }));
118 }
119
Hai Zhangb7776682018-09-25 15:10:57 -0700120 private static final class Connection implements ServiceConnection {
121
Hai Zhang527dd512018-10-19 11:41:33 -0700122 private static final long UNBIND_DELAY_MILLIS = 15 * 1000;
Hai Zhangb7776682018-09-25 15:10:57 -0700123
124 @UserIdInt
125 private final int mUserId;
126
127 @NonNull
128 private final Context mContext;
129
Hai Zhangfcbc3382018-12-06 15:34:05 -0800130 @NonNull
131 private final Handler mHandler = FgThread.getHandler();
132
Hai Zhangb7776682018-09-25 15:10:57 -0700133 private boolean mBound;
134
135 @Nullable
136 private IRoleControllerService mService;
137
138 @NonNull
139 private final Queue<Call> mPendingCalls = new ArrayDeque<>();
140
141 @NonNull
142 private final Runnable mUnbindRunnable = this::unbind;
143
144 Connection(@UserIdInt int userId, @NonNull Context context) {
145 mUserId = userId;
146 mContext = context;
147 }
148
Hai Zhangb7776682018-09-25 15:10:57 -0700149 @Override
Eugene Suslaa4200f822018-11-09 18:06:43 -0800150 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700151 public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) {
152 mService = IRoleControllerService.Stub.asInterface(service);
153 executePendingCalls();
154 }
155
Eugene Suslaa4200f822018-11-09 18:06:43 -0800156 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700157 private void executePendingCalls() {
158 while (!mPendingCalls.isEmpty()) {
159 Call call = mPendingCalls.poll();
160 call.execute(mService);
161 }
162 scheduleUnbind();
163 }
164
Hai Zhangb7776682018-09-25 15:10:57 -0700165 @Override
Eugene Suslaa4200f822018-11-09 18:06:43 -0800166 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700167 public void onServiceDisconnected(@NonNull ComponentName name) {
168 mService = null;
169 }
170
Hai Zhangb7776682018-09-25 15:10:57 -0700171 @Override
Eugene Suslaa4200f822018-11-09 18:06:43 -0800172 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700173 public void onBindingDied(@NonNull ComponentName name) {
174 unbind();
175 }
176
177 public void enqueueCall(@NonNull Call call) {
Eugene Suslaa4200f822018-11-09 18:06:43 -0800178 if (DEBUG) {
179 Slog.i(LOG_TAG, "Enqueue " + call);
180 }
Hai Zhangfcbc3382018-12-06 15:34:05 -0800181 mHandler.executeOrSendMessage(PooledLambda.obtainMessage(Connection::executeCall, this,
182 call));
Hai Zhangb7776682018-09-25 15:10:57 -0700183 }
184
Eugene Suslaa4200f822018-11-09 18:06:43 -0800185 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700186 private void executeCall(@NonNull Call call) {
187 ensureBound();
188 if (mService == null) {
Eugene Suslaa4200f822018-11-09 18:06:43 -0800189 if (DEBUG) {
190 Slog.i(LOG_TAG, "Delaying until service connected: " + call);
191 }
Hai Zhangb7776682018-09-25 15:10:57 -0700192 mPendingCalls.offer(call);
193 return;
194 }
195 call.execute(mService);
196 scheduleUnbind();
197 }
198
Eugene Suslaa4200f822018-11-09 18:06:43 -0800199 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700200 private void ensureBound() {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800201 mHandler.removeCallbacks(mUnbindRunnable);
Hai Zhangb7776682018-09-25 15:10:57 -0700202 if (!mBound) {
203 Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
204 intent.setPackage(mContext.getPackageManager()
205 .getPermissionControllerPackageName());
Eugene Suslaa4200f822018-11-09 18:06:43 -0800206 // Use direct handler to ensure onServiceConnected callback happens in the same
207 // call frame, as required by onGrantDefaultRoles
208 //
209 // Note that as a result, onServiceConnected may happen not on main thread!
Hai Zhangb7776682018-09-25 15:10:57 -0700210 mBound = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
Hai Zhangfcbc3382018-12-06 15:34:05 -0800211 mHandler, UserHandle.of(mUserId));
Hai Zhangb7776682018-09-25 15:10:57 -0700212 }
213 }
214
215 private void scheduleUnbind() {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800216 mHandler.removeCallbacks(mUnbindRunnable);
217 mHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS);
Hai Zhangb7776682018-09-25 15:10:57 -0700218 }
219
Eugene Suslaa4200f822018-11-09 18:06:43 -0800220 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700221 private void unbind() {
222 if (mBound) {
223 mService = null;
224 mContext.unbindService(this);
225 mBound = false;
226 }
227 }
228
229 public static class Call {
230
Hai Zhang527dd512018-10-19 11:41:33 -0700231 private static final int TIMEOUT_MILLIS = 15 * 1000;
Hai Zhangb7776682018-09-25 15:10:57 -0700232
233 @NonNull
Hai Zhang527dd512018-10-19 11:41:33 -0700234 private final CallExecutor mCallExecutor;
Hai Zhangb7776682018-09-25 15:10:57 -0700235
Hai Zhang527dd512018-10-19 11:41:33 -0700236 @NonNull
237 private final IRoleManagerCallback mCallback;
238
239 @NonNull
Hai Zhangfcbc3382018-12-06 15:34:05 -0800240 private final Handler mHandler = FgThread.getHandler();
241
242 @NonNull
Hai Zhangb295ac42018-11-16 16:08:18 -0800243 private final Runnable mTimeoutRunnable = this::notifyTimeout;
Hai Zhang527dd512018-10-19 11:41:33 -0700244
245 private boolean mCallbackNotified;
246
Eugene Susla92b88c72019-01-11 13:31:20 -0800247 @Nullable
248 private final String mDebugName;
249
Hai Zhang527dd512018-10-19 11:41:33 -0700250 private Call(@NonNull CallExecutor callExecutor,
251 @NonNull IRoleManagerCallback callback) {
252 mCallExecutor = callExecutor;
253 mCallback = callback;
Eugene Susla92b88c72019-01-11 13:31:20 -0800254 mDebugName = DEBUG
255 ? Arrays.stream(Thread.currentThread().getStackTrace())
256 .filter(s -> s.getClassName().equals(
257 RemoteRoleControllerService.class.getName()))
258 .findFirst()
259 .get()
260 .getMethodName()
261 : null;
Hai Zhangb7776682018-09-25 15:10:57 -0700262 }
263
Eugene Suslaa4200f822018-11-09 18:06:43 -0800264 @WorkerThread
Hai Zhangb7776682018-09-25 15:10:57 -0700265 public void execute(IRoleControllerService service) {
Eugene Suslaa4200f822018-11-09 18:06:43 -0800266 if (DEBUG) {
267 Slog.i(LOG_TAG, "Executing " + this);
268 }
Hai Zhangb7776682018-09-25 15:10:57 -0700269 try {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800270 mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MILLIS);
Hai Zhang527dd512018-10-19 11:41:33 -0700271 mCallExecutor.execute(service, new CallbackDelegate());
272 } catch (RemoteException e) {
273 Slog.e(LOG_TAG, "Error calling RoleControllerService", e);
274 notifyCallback(false);
275 }
276 }
277
Eugene Suslaa4200f822018-11-09 18:06:43 -0800278 @WorkerThread
Hai Zhangb295ac42018-11-16 16:08:18 -0800279 private void notifyTimeout() {
280 Slog.e(LOG_TAG, "Call timed out, calling onFailure()");
281 notifyCallback(false);
282 }
283
284 @WorkerThread
Hai Zhang527dd512018-10-19 11:41:33 -0700285 private void notifyCallback(boolean success) {
Eugene Susla92b88c72019-01-11 13:31:20 -0800286 if (DEBUG) {
287 Log.i(LOG_TAG, "notifyCallback(" + this
288 + ", success = " + success + ")");
289 }
Hai Zhang527dd512018-10-19 11:41:33 -0700290 if (mCallbackNotified) {
291 return;
292 }
293 mCallbackNotified = true;
Hai Zhangfcbc3382018-12-06 15:34:05 -0800294 mHandler.removeCallbacks(mTimeoutRunnable);
Hai Zhang527dd512018-10-19 11:41:33 -0700295 try {
296 if (success) {
297 mCallback.onSuccess();
298 } else {
299 mCallback.onFailure();
Hai Zhangb7776682018-09-25 15:10:57 -0700300 }
Hai Zhang527dd512018-10-19 11:41:33 -0700301 } catch (RemoteException e) {
302 Slog.e(LOG_TAG, "Error calling " + (success ? "onSuccess()" : "onFailure()")
303 + " callback", e);
304 }
305 }
306
Eugene Suslaa4200f822018-11-09 18:06:43 -0800307 @Override
308 public String toString() {
Eugene Susla92b88c72019-01-11 13:31:20 -0800309 return DEBUG ? mDebugName : "Call with callback: " + mCallback;
Eugene Suslaa4200f822018-11-09 18:06:43 -0800310 }
311
Hai Zhang527dd512018-10-19 11:41:33 -0700312 @FunctionalInterface
313 public interface CallExecutor {
314
Eugene Suslaa4200f822018-11-09 18:06:43 -0800315 @WorkerThread
Hai Zhang527dd512018-10-19 11:41:33 -0700316 void execute(IRoleControllerService service, IRoleManagerCallback callbackDelegate)
317 throws RemoteException;
318 }
319
320 private class CallbackDelegate extends IRoleManagerCallback.Stub {
321
322 @Override
323 public void onSuccess() throws RemoteException {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800324 mHandler.sendMessage(PooledLambda.obtainMessage(Call::notifyCallback, Call.this,
325 true));
Hai Zhang527dd512018-10-19 11:41:33 -0700326 }
327
328 @Override
329 public void onFailure() throws RemoteException {
Hai Zhangfcbc3382018-12-06 15:34:05 -0800330 mHandler.sendMessage(PooledLambda.obtainMessage(Call::notifyCallback, Call.this,
331 false));
Hai Zhangb7776682018-09-25 15:10:57 -0700332 }
333 }
334 }
335 }
336}