• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.server.devicelock;
18 
19 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ResolveInfo;
28 import android.content.pm.ServiceInfo;
29 import android.content.res.Resources;
30 import android.os.UserHandle;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 
34 import java.util.List;
35 
36 /**
37  * Utility class to find properties of the device lock controller package.
38  */
39 public final class DeviceLockControllerPackageUtils {
40     private final Context mContext;
41 
42     private static final String SERVICE_ACTION =
43             "android.app.action.DEVICE_LOCK_CONTROLLER_SERVICE";
44 
DeviceLockControllerPackageUtils(Context context)45     public DeviceLockControllerPackageUtils(Context context) {
46         mContext = context;
47     }
48 
49     private ServiceInfo mServiceInfo;
50 
51     private int mDeviceIdTypeBitmap = -1;
52 
53     /**
54      * Find the service for device lock controller.
55      *
56      * @param errorMessage Reason why the service could not be found.
57      * @return Service information or null for an error.
58      */
59     @VisibleForTesting(visibility = PACKAGE)
60     @Nullable
findService(@onNull StringBuilder errorMessage)61     public synchronized ServiceInfo findService(@NonNull StringBuilder errorMessage) {
62         errorMessage.setLength(0);
63 
64         if (mServiceInfo == null) {
65             mServiceInfo = findServiceInternal(errorMessage);
66         }
67 
68         return mServiceInfo;
69     }
70 
71     @Nullable
findServiceInternal(@onNull StringBuilder errorMessage)72     private ServiceInfo findServiceInternal(@NonNull StringBuilder errorMessage) {
73         final Intent intent = new Intent(SERVICE_ACTION);
74         final PackageManager pm = mContext.getPackageManager();
75 
76         errorMessage.setLength(0);
77 
78         final List<ResolveInfo> resolveInfoList = pm.queryIntentServicesAsUser(intent,
79                 PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
80                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
81                         | PackageManager.MATCH_DISABLED_COMPONENTS, UserHandle.SYSTEM);
82 
83         if (resolveInfoList == null || resolveInfoList.isEmpty()) {
84             errorMessage.append("Service with " + SERVICE_ACTION + " not found.");
85 
86             return null;
87         }
88 
89         ServiceInfo resultServiceInfo = null;
90 
91         for (ResolveInfo resolveInfo : resolveInfoList) {
92             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
93 
94             if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
95                 continue;
96             }
97 
98             if (resultServiceInfo != null) {
99                 errorMessage.append("Multiple system services handle " + SERVICE_ACTION + ".");
100 
101                 return null;
102             }
103 
104             resultServiceInfo = serviceInfo;
105         }
106 
107         if (!resultServiceInfo.applicationInfo.isPrivilegedApp()) {
108             errorMessage.append("Device lock controller must be a privileged app");
109 
110             return null;
111         }
112 
113         return resultServiceInfo;
114     }
115 
116     /**
117      * Get the allowed device id type bitmap or -1 if it cannot be determined.
118      */
119     @VisibleForTesting
getDeviceIdTypeBitmap(@onNull StringBuilder errorMessage)120     public synchronized int getDeviceIdTypeBitmap(@NonNull StringBuilder errorMessage) {
121         errorMessage.setLength(0);
122 
123         if (mDeviceIdTypeBitmap < 0) {
124             mDeviceIdTypeBitmap = getDeviceIdTypeBitmapInternal(errorMessage);
125         }
126 
127         return mDeviceIdTypeBitmap;
128     }
129 
getDeviceIdTypeBitmapInternal(@onNull StringBuilder errorMessage)130     private int getDeviceIdTypeBitmapInternal(@NonNull StringBuilder errorMessage) {
131         ServiceInfo serviceInfo = findService(errorMessage);
132 
133         if (serviceInfo == null) {
134             return -1;
135         }
136 
137         final String packageName = serviceInfo.packageName;
138 
139         final PackageManager pm = mContext.getPackageManager();
140         int deviceIdTypeBitmap = -1;
141         errorMessage.setLength(0);
142 
143         try {
144             final Resources resources = pm.getResourcesForApplication(packageName);
145             final int resId = resources.getIdentifier("device_id_type_bitmap", "integer",
146                     packageName);
147             if (resId == 0) {
148                 errorMessage.append("Cannot get device_id_type_bitmap from: " + packageName);
149 
150                 return -1;
151             }
152             deviceIdTypeBitmap = resources.getInteger(resId);
153         } catch (PackageManager.NameNotFoundException e) {
154             errorMessage.append("Cannot get resources for package: " + packageName);
155         }
156 
157         return deviceIdTypeBitmap;
158     }
159 }
160