blob: b60db84ec6550da4e442b7e4ecd77e68913b5caf [file] [log] [blame]
Ram Periathiruvadiacb60242017-04-13 16:19:09 -07001/*
2 * Copyright (C) 2015 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.car;
18
Eric Jeonga84a6822019-09-17 15:46:38 -070019import android.car.IPerUserCarService;
Antonio Kantekf7007532020-03-17 10:37:58 -070020import android.car.user.CarUserManager;
21import android.car.user.CarUserManager.UserLifecycleListener;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070022import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070025import android.content.ServiceConnection;
26import android.os.IBinder;
27import android.os.UserHandle;
Felipe Leme176a5fd2021-01-20 15:48:33 -080028import android.util.IndentingPrintWriter;
Eric Jeongbd5fb562020-12-21 13:49:40 -080029import android.util.Slog;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070030
Mayank Garg31e73042020-01-23 00:10:38 -080031import com.android.car.user.CarUserService;
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -070032import com.android.internal.annotations.GuardedBy;
33
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070034import java.util.ArrayList;
Eric Jeonga84a6822019-09-17 15:46:38 -070035import java.util.List;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070036
37/**
38 * A Helper class that helps with the following:
39 * 1. Provide methods to Bind/Unbind to the {@link PerUserCarService} as the current User
40 * 2. Set up a listener to UserSwitch Broadcasts and call clients that have registered callbacks.
41 *
42 */
Ram Periathiruvadia048c0a2017-05-09 07:35:03 -070043public class PerUserCarServiceHelper implements CarServiceBase {
Felipe Leme176a5fd2021-01-20 15:48:33 -080044
Mayank Garg72c71d22021-02-03 23:54:45 -080045 private static final String TAG = CarLog.tagFor(PerUserCarServiceHelper.class);
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070046 private static boolean DBG = false;
Felipe Leme176a5fd2021-01-20 15:48:33 -080047
Mayank Garg31e73042020-01-23 00:10:38 -080048 private final Context mContext;
49 private final CarUserService mUserService;
Eric Jeonga84a6822019-09-17 15:46:38 -070050 private IPerUserCarService mPerUserCarService;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070051 // listener to call on a ServiceConnection to PerUserCarService
52 private List<ServiceCallback> mServiceCallbacks;
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -070053 private final Object mServiceBindLock = new Object();
54 @GuardedBy("mServiceBindLock")
Felipe Leme176a5fd2021-01-20 15:48:33 -080055 private boolean mBound;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070056
Mayank Garg31e73042020-01-23 00:10:38 -080057 public PerUserCarServiceHelper(Context context, CarUserService userService) {
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070058 mContext = context;
59 mServiceCallbacks = new ArrayList<>();
Mayank Garg31e73042020-01-23 00:10:38 -080060 mUserService = userService;
Antonio Kantekf7007532020-03-17 10:37:58 -070061 mUserService.addUserLifecycleListener(mUserLifecycleListener);
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070062 }
63
Ram Periathiruvadia048c0a2017-05-09 07:35:03 -070064 @Override
Christophe Koessler69143262021-02-24 21:08:34 +000065 public void init() {
66 synchronized (mServiceBindLock) {
67 bindToPerUserCarService();
68 }
69 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070070
Ram Periathiruvadia048c0a2017-05-09 07:35:03 -070071 @Override
Yan Zhu211b1fe2019-11-06 15:54:19 -080072 public void release() {
73 synchronized (mServiceBindLock) {
74 unbindFromPerUserCarService();
Antonio Kantekf7007532020-03-17 10:37:58 -070075 mUserService.removeUserLifecycleListener(mUserLifecycleListener);
Yan Zhu211b1fe2019-11-06 15:54:19 -080076 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070077 }
Ram Periathiruvadia048c0a2017-05-09 07:35:03 -070078
Antonio Kantekf7007532020-03-17 10:37:58 -070079 private final UserLifecycleListener mUserLifecycleListener = event -> {
80 if (DBG) {
Eric Jeongbd5fb562020-12-21 13:49:40 -080081 Slog.d(TAG, "onEvent(" + event + ")");
Mayank Garg31e73042020-01-23 00:10:38 -080082 }
Christophe Koessler69143262021-02-24 21:08:34 +000083 if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
84 List<ServiceCallback> callbacks;
85 int userId = event.getUserId();
86 if (DBG) {
87 Slog.d(TAG, "User Switch Happened. New User" + userId);
88 }
Mayank Garg31e73042020-01-23 00:10:38 -080089
Christophe Koessler69143262021-02-24 21:08:34 +000090 // Before unbinding, notify the callbacks about unbinding from the service
91 // so the callbacks can clean up their state through the binder before the service is
92 // killed.
93 synchronized (mServiceBindLock) {
94 // copy the callbacks
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070095 callbacks = new ArrayList<>(mServiceCallbacks);
96 }
Christophe Koessler69143262021-02-24 21:08:34 +000097 // call them
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070098 for (ServiceCallback callback : callbacks) {
99 callback.onPreUnbind();
100 }
Christophe Koessler69143262021-02-24 21:08:34 +0000101 // unbind from the service running as the previous user.
Christophe Koessler47a64c42020-12-09 14:19:34 -0800102 unbindFromPerUserCarService();
Christophe Koessler69143262021-02-24 21:08:34 +0000103 // bind to the service running as the new user
104 bindToPerUserCarService();
Christophe Koessler47a64c42020-12-09 14:19:34 -0800105 }
Mayank Garg31e73042020-01-23 00:10:38 -0800106 };
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700107
108 /**
109 * ServiceConnection to detect connecting/disconnecting to {@link PerUserCarService}
110 */
111 private final ServiceConnection mUserServiceConnection = new ServiceConnection() {
112 // On connecting to the service, get the binder object to the CarBluetoothService
113 @Override
114 public void onServiceConnected(ComponentName componentName, IBinder service) {
115 List<ServiceCallback> callbacks;
116 if (DBG) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800117 Slog.d(TAG, "Connected to User Service");
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700118 }
Eric Jeonga84a6822019-09-17 15:46:38 -0700119 mPerUserCarService = IPerUserCarService.Stub.asInterface(service);
120 if (mPerUserCarService != null) {
Yan Zhu211b1fe2019-11-06 15:54:19 -0800121 synchronized (mServiceBindLock) {
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700122 // copy the callbacks
123 callbacks = new ArrayList<>(mServiceCallbacks);
124 }
125 // call them
126 for (ServiceCallback callback : callbacks) {
Eric Jeonga84a6822019-09-17 15:46:38 -0700127 callback.onServiceConnected(mPerUserCarService);
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700128 }
129 }
130 }
131
132 @Override
133 public void onServiceDisconnected(ComponentName componentName) {
134 List<ServiceCallback> callbacks;
135 if (DBG) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800136 Slog.d(TAG, "Disconnected from User Service");
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700137 }
Yan Zhu211b1fe2019-11-06 15:54:19 -0800138 synchronized (mServiceBindLock) {
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700139 // copy the callbacks
140 callbacks = new ArrayList<>(mServiceCallbacks);
141 }
142 // call them
143 for (ServiceCallback callback : callbacks) {
144 callback.onServiceDisconnected();
145 }
146 }
147 };
148
149 /**
Eric Jeonga84a6822019-09-17 15:46:38 -0700150 * Bind to the PerUserCarService {@link PerUserCarService} which is created to run as the
151 * Current User.
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700152 */
153 private void bindToPerUserCarService() {
154 if (DBG) {
Christophe Koessler69143262021-02-24 21:08:34 +0000155 Slog.d(TAG, "Binding to User service");
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700156 }
157 Intent startIntent = new Intent(mContext, PerUserCarService.class);
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -0700158 synchronized (mServiceBindLock) {
159 mBound = true;
160 boolean bindSuccess = mContext.bindServiceAsUser(startIntent, mUserServiceConnection,
Christophe Koessler69143262021-02-24 21:08:34 +0000161 mContext.BIND_AUTO_CREATE, UserHandle.CURRENT);
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -0700162 // If valid connection not obtained, unbind
163 if (!bindSuccess) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800164 Slog.e(TAG, "bindToPerUserCarService() failed to get valid connection");
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -0700165 unbindFromPerUserCarService();
166 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700167 }
168 }
169
170 /**
171 * Unbind from the {@link PerUserCarService} running as the Current user.
172 */
173 private void unbindFromPerUserCarService() {
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -0700174 synchronized (mServiceBindLock) {
175 // mBound flag makes sure we are unbinding only when the service is bound.
176 if (mBound) {
177 if (DBG) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800178 Slog.d(TAG, "Unbinding from User Service");
Ram Periathiruvadiee7c58a2017-05-30 15:31:07 -0700179 }
180 mContext.unbindService(mUserServiceConnection);
181 mBound = false;
182 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700183 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700184 }
185
186 /**
187 * Register a listener that gets called on Connection state changes to the
188 * {@link PerUserCarService}
189 * @param listener - Callback to invoke on user switch event.
190 */
191 public void registerServiceCallback(ServiceCallback listener) {
192 if (listener != null) {
193 if (DBG) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800194 Slog.d(TAG, "Registering PerUserCarService Listener");
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700195 }
Yan Zhu211b1fe2019-11-06 15:54:19 -0800196 synchronized (mServiceBindLock) {
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700197 mServiceCallbacks.add(listener);
198 }
199 }
200 }
201
202 /**
203 * Unregister the Service Listener
204 * @param listener - Callback method to unregister
205 */
206 public void unregisterServiceCallback(ServiceCallback listener) {
207 if (DBG) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800208 Slog.d(TAG, "Unregistering PerUserCarService Listener");
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700209 }
210 if (listener != null) {
Yan Zhu211b1fe2019-11-06 15:54:19 -0800211 synchronized (mServiceBindLock) {
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700212 mServiceCallbacks.remove(listener);
213 }
214 }
215 }
216
217 /**
218 * Listener to the PerUserCarService connection status that clients need to implement.
219 */
220 public interface ServiceCallback {
Eric Jeonga84a6822019-09-17 15:46:38 -0700221 /**
222 * Invoked when a service connects.
223 *
224 * @param perUserCarService the instance of IPerUserCarService.
225 */
226 void onServiceConnected(IPerUserCarService perUserCarService);
227
228 /**
229 * Invoked before an unbind call is going to be made.
230 */
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700231 void onPreUnbind();
Eric Jeonga84a6822019-09-17 15:46:38 -0700232
233 /**
234 * Invoked when a service is crashed or disconnected.
235 */
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700236 void onServiceDisconnected();
237 }
Ram Periathiruvadia048c0a2017-05-09 07:35:03 -0700238
239 @Override
Felipe Leme176a5fd2021-01-20 15:48:33 -0800240 public final void dump(IndentingPrintWriter pw) {
241 pw.println("PerUserCarServiceHelper");
242 pw.increaseIndent();
243 synchronized (mServiceBindLock) {
244 pw.printf("bound: %b\n", mBound);
245 if (mServiceCallbacks == null) {
246 pw.println("no callbacks");
247 } else {
248 int size = mServiceCallbacks.size();
249 pw.printf("%d callback%s\n", size, (size > 1 ? "s" : ""));
250 }
251 }
252 pw.decreaseIndent();
Ram Periathiruvadia048c0a2017-05-09 07:35:03 -0700253 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700254}