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