• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 com.android.car.admin;
18 
19 import static com.android.car.PermissionHelper.checkHasDumpPermissionGranted;
20 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
21 
22 import android.annotation.IntDef;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.UserIdInt;
26 import android.app.ActivityManager;
27 import android.app.admin.DevicePolicyManager;
28 import android.car.admin.CarDevicePolicyManager;
29 import android.car.admin.ICarDevicePolicyService;
30 import android.car.builtin.os.UserManagerHelper;
31 import android.car.builtin.util.Slogf;
32 import android.car.user.UserCreationResult;
33 import android.car.user.UserRemovalResult;
34 import android.car.user.UserStartResult;
35 import android.car.user.UserStopResult;
36 import android.car.util.concurrent.AndroidFuture;
37 import android.content.BroadcastReceiver;
38 import android.content.Context;
39 import android.content.Intent;
40 import android.content.IntentFilter;
41 import android.content.pm.PackageManager;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.util.SparseIntArray;
45 
46 import com.android.car.BuiltinPackageDependency;
47 import com.android.car.CarLog;
48 import com.android.car.CarServiceBase;
49 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
50 import com.android.car.internal.common.UserHelperLite;
51 import com.android.car.internal.os.CarSystemProperties;
52 import com.android.car.internal.util.DebugUtils;
53 import com.android.car.internal.util.IndentingPrintWriter;
54 import com.android.car.user.CarUserService;
55 import com.android.internal.annotations.GuardedBy;
56 import com.android.internal.annotations.VisibleForTesting;
57 
58 import java.lang.annotation.Retention;
59 import java.lang.annotation.RetentionPolicy;
60 
61 /**
62  * Service for device policy related features.
63  */
64 public final class CarDevicePolicyService extends ICarDevicePolicyService.Stub
65         implements CarServiceBase {
66 
67     @VisibleForTesting
68     static final String TAG = CarLog.tagFor(CarDevicePolicyService.class);
69 
70     private static final int HAL_TIMEOUT_MS = CarSystemProperties.getUserHalTimeout().orElse(5_000);
71     private static final String PREFIX_NEW_USER_DISCLAIMER_STATUS = "NEW_USER_DISCLAIMER_STATUS_";
72 
73     // TODO(b/175057848) must be public because of DebugUtils.constantToString()
74     public static final int NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED = 0;
75     public static final int NEW_USER_DISCLAIMER_STATUS_RECEIVED = 1;
76     public static final int NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT = 2;
77     public static final int NEW_USER_DISCLAIMER_STATUS_SHOWN = 3;
78     public static final int NEW_USER_DISCLAIMER_STATUS_ACKED = 4;
79 
80     private final Object mLock = new Object();
81     private final CarUserService mCarUserService;
82     private final Context mContext;
83     private final Context mCarServiceBuiltinPackageContext;
84 
85     @Retention(RetentionPolicy.SOURCE)
86     @IntDef(flag = false, prefix = { PREFIX_NEW_USER_DISCLAIMER_STATUS }, value = {
87             NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED,
88             NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT,
89             NEW_USER_DISCLAIMER_STATUS_RECEIVED,
90             NEW_USER_DISCLAIMER_STATUS_SHOWN,
91             NEW_USER_DISCLAIMER_STATUS_ACKED
92     })
93     public @interface NewUserDisclaimerStatus {}
94 
95     @GuardedBy("sLock")
96     private final SparseIntArray mUserDisclaimerStatusPerUser = new SparseIntArray();
97 
98     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
99         @Override
100         public void onReceive(Context context, Intent intent) {
101             int userId = ActivityManager.getCurrentUser();
102             Slogf.d(TAG, "Received intent for user " + userId + ": " + intent);
103             if (!mContext.getPackageManager()
104                     .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
105                 Slogf.d(TAG, "Not handling ACTION_SHOW_NEW_USER_DISCLAIMER because device "
106                         + "doesn't have %s", PackageManager.FEATURE_DEVICE_ADMIN);
107                 return;
108             }
109             switch(intent.getAction()) {
110                 case DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER:
111                     Slogf.d(TAG, "Action show new user disclaimer");
112                     setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_RECEIVED);
113                     showNewUserDisclaimer(userId);
114                     break;
115                 default:
116                     Slogf.w(TAG, "received unexpected intent: %s" , intent);
117             }
118         }
119     };
120 
CarDevicePolicyService(@onNull Context context, @NonNull Context carServiceBuiltinPackageContext, @NonNull CarUserService carUserService)121     public CarDevicePolicyService(@NonNull Context context,
122             @NonNull Context carServiceBuiltinPackageContext,
123             @NonNull CarUserService carUserService) {
124         mCarUserService = carUserService;
125         mContext = context;
126         mCarServiceBuiltinPackageContext = carServiceBuiltinPackageContext;
127     }
128 
129     @Override
init()130     public void init() {
131         Slogf.d(TAG, "init()");
132         mContext.registerReceiverForAllUsers(mBroadcastReceiver,
133                 new IntentFilter(DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER),
134                 /* broadcastPermissions= */ null, /* scheduler= */ null,
135                 Context.RECEIVER_NOT_EXPORTED);
136     }
137 
138     @Override
release()139     public void release() {
140         Slogf.d(TAG, "release()");
141         mContext.unregisterReceiver(mBroadcastReceiver);
142     }
143 
144     @Override
removeUser(@serIdInt int userId, AndroidFuture<UserRemovalResult> receiver)145     public void removeUser(@UserIdInt int userId, AndroidFuture<UserRemovalResult> receiver) {
146         mCarUserService.removeUser(userId, /* hasCallerRestrictions= */ true, receiver);
147     }
148 
149     @Override
createUser(@ullable String name, @CarDevicePolicyManager.UserType int type, AndroidFuture<UserCreationResult> receiver)150     public void createUser(@Nullable String name,
151             @CarDevicePolicyManager.UserType int type, AndroidFuture<UserCreationResult> receiver) {
152         int userInfoFlags = 0;
153         String userType = UserManager.USER_TYPE_FULL_SECONDARY;
154         switch(type) {
155             case CarDevicePolicyManager.USER_TYPE_REGULAR:
156                 break;
157             case CarDevicePolicyManager.USER_TYPE_ADMIN:
158                 userInfoFlags = UserManagerHelper.FLAG_ADMIN;
159                 break;
160             case CarDevicePolicyManager.USER_TYPE_GUEST:
161                 userType = UserManager.USER_TYPE_FULL_GUEST;
162                 break;
163             default:
164                 Slogf.d(TAG, "createUser(): invalid userType (%s) / flags (%08x) "
165                         + "combination", userType, userInfoFlags);
166                 receiver.complete(
167                         new UserCreationResult(UserCreationResult.STATUS_INVALID_REQUEST));
168                 return;
169         }
170 
171         Slogf.d(TAG, "calling createUser(%s, %s, %d, %d)",
172                 UserHelperLite.safeName(name), userType, userInfoFlags, HAL_TIMEOUT_MS);
173 
174         mCarUserService.createUser(name, userType, userInfoFlags, HAL_TIMEOUT_MS, receiver);
175     }
176 
177     @Override
startUserInBackground(@serIdInt int userId, AndroidFuture<UserStartResult> receiver)178     public void startUserInBackground(@UserIdInt int userId,
179             AndroidFuture<UserStartResult> receiver) {
180         mCarUserService.startUserInBackground(userId, receiver);
181     }
182 
183     @Override
stopUser(@serIdInt int userId, AndroidFuture<UserStopResult> receiver)184     public void stopUser(@UserIdInt int userId, AndroidFuture<UserStopResult> receiver) {
185         mCarUserService.stopUser(userId, receiver);
186     }
187 
188     @Override
189     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(@onNull IndentingPrintWriter writer)190     public void dump(@NonNull IndentingPrintWriter writer) {
191         checkHasDumpPermissionGranted(mContext, "dump()");
192 
193         writer.println("*CarDevicePolicyService*");
194 
195         synchronized (mLock) {
196             int numUsers = mUserDisclaimerStatusPerUser.size();
197             writer.println("**mDisclaimerStatusPerUser**");
198             for (int i = 0; i < numUsers; i++) {
199                 int userId = mUserDisclaimerStatusPerUser.keyAt(i);
200                 int status = mUserDisclaimerStatusPerUser.get(userId);
201                 writer.printf("userId=%d disclaimerStatus=%s\n", userId,
202                         newUserDisclaimerStatusToString(status));
203             }
204         }
205 
206         writer.printf("HAL_TIMEOUT_MS: %d\n", HAL_TIMEOUT_MS);
207     }
208 
209     /**
210      * Updates the internal state with the disclaimer status as shown.
211      */
212     @Override
setUserDisclaimerShown(int userId)213     public void setUserDisclaimerShown(int userId) {
214         setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_SHOWN);
215     }
216 
217     /**
218      * Updates the internal state with the disclaimer status as acknowledged.
219      */
220     @Override
setUserDisclaimerAcknowledged(int userId)221     public void setUserDisclaimerAcknowledged(int userId) {
222         setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_ACKED);
223         UserHandle user = UserHandle.of(userId);
224         BuiltinPackageDependency.createNotificationHelper(mCarServiceBuiltinPackageContext)
225                 .cancelUserDisclaimerNotification(user);
226 
227         DevicePolicyManager dpm = mContext.createContextAsUser(user, 0)
228                 .getSystemService(DevicePolicyManager.class);
229         dpm.acknowledgeNewUserDisclaimer();
230     }
231 
232     @VisibleForTesting
233     @NewUserDisclaimerStatus
getNewUserDisclaimerStatus(int userId)234     int getNewUserDisclaimerStatus(int userId) {
235         synchronized (mLock) {
236             return mUserDisclaimerStatusPerUser.get(userId,
237                     NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED);
238         }
239     }
240 
showNewUserDisclaimer(@serIdInt int userId)241     private void showNewUserDisclaimer(@UserIdInt int userId) {
242         // TODO(b/175057848) persist status so it's shown again if car service crashes?
243 
244         BuiltinPackageDependency.createNotificationHelper(mCarServiceBuiltinPackageContext)
245                 .showUserDisclaimerNotification(UserHandle.of(userId));
246 
247         setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT);
248     }
249 
setUserDisclaimerStatus(@serIdInt int userId, @NewUserDisclaimerStatus int status)250     private void setUserDisclaimerStatus(@UserIdInt int userId,
251             @NewUserDisclaimerStatus int status) {
252         synchronized (mLock) {
253             Slogf.d(TAG, "Changing status from %s to %s",
254                     newUserDisclaimerStatusToString(
255                             mUserDisclaimerStatusPerUser.get(
256                                     userId, NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED)),
257                     newUserDisclaimerStatusToString(status));
258             mUserDisclaimerStatusPerUser.put(userId, status);
259         }
260     }
261 
262     @VisibleForTesting
newUserDisclaimerStatusToString(@ewUserDisclaimerStatus int status)263     static String newUserDisclaimerStatusToString(@NewUserDisclaimerStatus int status) {
264         return DebugUtils.constantToString(CarDevicePolicyService.class,
265                 PREFIX_NEW_USER_DISCLAIMER_STATUS, status);
266     }
267 }
268