blob: b2b811624fe5731386a4b8dfbce541b5dea46bd3 [file] [log] [blame]
Sander Alewijnsed5e4c422014-11-25 17:56:16 +00001/*
2 * Copyright 2014, 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.managedprovisioning;
18
Joe Delfino84e56f52015-03-27 09:56:18 -040019import android.app.admin.DevicePolicyManager;
Alan Treadway9a42f2b2015-02-25 15:12:31 +000020import android.content.ComponentName;
Nicolas Prevot0b447252015-03-09 14:59:02 +000021import android.content.Context;
Alan Treadway9a42f2b2015-02-25 15:12:31 +000022import android.content.Intent;
Nicolas Prevot0b447252015-03-09 14:59:02 +000023import android.content.pm.ActivityInfo;
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000024import android.content.pm.ApplicationInfo;
25import android.content.pm.IPackageManager;
Nicolas Prevot0b447252015-03-09 14:59:02 +000026import android.content.pm.PackageInfo;
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000027import android.content.pm.PackageManager;
Nicolas Prevot0b447252015-03-09 14:59:02 +000028import android.content.pm.PackageManager.NameNotFoundException;
Joe Delfino84e56f52015-03-27 09:56:18 -040029import android.content.pm.UserInfo;
Alan Treadway9a42f2b2015-02-25 15:12:31 +000030import android.graphics.drawable.Drawable;
Joe Delfino84e56f52015-03-27 09:56:18 -040031import android.os.Binder;
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000032import android.os.RemoteException;
33import android.os.ServiceManager;
Joe Delfinod0f29282015-03-19 08:26:09 -040034import android.os.UserHandle;
Joe Delfino84e56f52015-03-27 09:56:18 -040035import android.os.UserManager;
Nicolas Prevot0b447252015-03-09 14:59:02 +000036import android.text.TextUtils;
Sander Alewijnse3efa83a2015-04-14 14:46:18 +010037import android.util.Base64;
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000038
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000039import java.util.HashSet;
Alan Treadway9a42f2b2015-02-25 15:12:31 +000040import java.util.List;
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000041import java.util.Set;
42
Alan Treadway9a42f2b2015-02-25 15:12:31 +000043import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
44import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
45
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000046/**
47 * Class containing various auxiliary methods.
48 */
49public class Utils {
Alan Treadway9a42f2b2015-02-25 15:12:31 +000050 private Utils() {}
51
Sander Alewijnsed5e4c422014-11-25 17:56:16 +000052 public static Set<String> getCurrentSystemApps(int userId) {
53 IPackageManager ipm = IPackageManager.Stub.asInterface(ServiceManager
54 .getService("package"));
55 Set<String> apps = new HashSet<String>();
56 List<ApplicationInfo> aInfos = null;
57 try {
58 aInfos = ipm.getInstalledApplications(
59 PackageManager.GET_UNINSTALLED_PACKAGES, userId).getList();
60 } catch (RemoteException neverThrown) {
61 ProvisionLogger.loge("This should not happen.", neverThrown);
62 }
63 for (ApplicationInfo aInfo : aInfos) {
64 if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
65 apps.add(aInfo.packageName);
66 }
67 }
68 return apps;
69 }
70
71 public static void disableComponent(ComponentName toDisable, int userId) {
72 try {
73 IPackageManager ipm = IPackageManager.Stub.asInterface(ServiceManager
74 .getService("package"));
75
76 ipm.setComponentEnabledSetting(toDisable,
77 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP,
78 userId);
79 } catch (RemoteException neverThrown) {
80 ProvisionLogger.loge("This should not happen.", neverThrown);
81 } catch (Exception e) {
82 ProvisionLogger.logw("Component not found, not disabling it: "
83 + toDisable.toShortString());
84 }
85 }
Nicolas Prevot0b447252015-03-09 14:59:02 +000086
87 public static ComponentName findDeviceAdminFromIntent(Intent intent, Context c)
88 throws IllegalProvisioningArgumentException {
89 ComponentName mdmComponentName = intent.getParcelableExtra(
90 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME);
91 String mdmPackageName = intent.getStringExtra(
92 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME);
93 return findDeviceAdmin(mdmPackageName, mdmComponentName, c);
94 }
95
96 /**
97 * Exception thrown when the provisioning has failed completely.
98 *
99 * We're using a custom exception to avoid catching subsequent exceptions that might be
100 * significant.
101 */
102 public static class IllegalProvisioningArgumentException extends Exception {
103 public IllegalProvisioningArgumentException(String message) {
104 super(message);
105 }
106
107 public IllegalProvisioningArgumentException(String message, Throwable t) {
108 super(message, t);
109 }
110 }
111
112 /**
113 * Check the validity of the admin component name supplied, or try to infer this componentName
114 * from the package.
115 *
116 * We are supporting lookup by package name for legacy reasons.
117 *
118 * If mdmComponentName is supplied (not null):
119 * mdmPackageName is ignored.
120 * Check that the package of mdmComponentName is installed, that mdmComponentName is a
121 * receiver in this package, and return it.
122 *
123 * Otherwise:
124 * mdmPackageName must be supplied (not null).
125 * Check that this package is installed, try to infer a potential device admin in this package,
126 * and return it.
127 */
128 public static ComponentName findDeviceAdmin(String mdmPackageName,
129 ComponentName mdmComponentName, Context c) throws IllegalProvisioningArgumentException {
130 if (mdmComponentName != null) {
131 mdmPackageName = mdmComponentName.getPackageName();
132 }
133 if (mdmPackageName == null) {
134 throw new IllegalProvisioningArgumentException("Neither the package name nor the"
135 + " component name of the admin are supplied");
136 }
137 PackageInfo pi;
138 try {
139 pi = c.getPackageManager().getPackageInfo(mdmPackageName,
140 PackageManager.GET_RECEIVERS);
141 } catch (NameNotFoundException e) {
142 throw new IllegalProvisioningArgumentException("Mdm "+ mdmPackageName
143 + " is not installed. ", e);
144 }
145 if (mdmComponentName != null) {
146 // If the component was specified in the intent: check that it is in the manifest.
147 checkAdminComponent(mdmComponentName, pi);
148 return mdmComponentName;
149 } else {
150 // Otherwise: try to find a potential device admin in the manifest.
151 return findDeviceAdminInPackage(mdmPackageName, pi);
152 }
153 }
154
155 private static void checkAdminComponent(ComponentName mdmComponentName, PackageInfo pi)
156 throws IllegalProvisioningArgumentException{
157 for (ActivityInfo ai : pi.receivers) {
158 if (mdmComponentName.getClassName().equals(ai.name)) {
159 return;
160 }
161 }
162 throw new IllegalProvisioningArgumentException("The component " + mdmComponentName
163 + " cannot be found");
164 }
165
166 private static ComponentName findDeviceAdminInPackage(String mdmPackageName, PackageInfo pi)
167 throws IllegalProvisioningArgumentException {
168 ComponentName mdmComponentName = null;
169 for (ActivityInfo ai : pi.receivers) {
170 if (!TextUtils.isEmpty(ai.permission) &&
171 ai.permission.equals(android.Manifest.permission.BIND_DEVICE_ADMIN)) {
172 if (mdmComponentName != null) {
173 throw new IllegalProvisioningArgumentException("There are several "
174 + "device admins in " + mdmPackageName + " but no one in specified");
175 } else {
176 mdmComponentName = new ComponentName(mdmPackageName, ai.name);
177 }
178 }
179 }
180 if (mdmComponentName == null) {
181 throw new IllegalProvisioningArgumentException("There are no device admins in"
182 + mdmPackageName);
183 }
184 return mdmComponentName;
185 }
Alan Treadway9a42f2b2015-02-25 15:12:31 +0000186
187 public static MdmPackageInfo getMdmPackageInfo(PackageManager pm, String packageName) {
188 if (packageName != null) {
189 try {
190 ApplicationInfo ai = pm.getApplicationInfo(packageName, /* default flags */ 0);
191 if (ai != null) {
192 return new MdmPackageInfo(pm.getApplicationIcon(packageName),
193 pm.getApplicationLabel(ai).toString());
194 }
195 } catch (PackageManager.NameNotFoundException e) {
196 // Package does not exist, ignore. Should never happen.
197 ProvisionLogger.loge("Package does not exist. Should never happen.");
198 }
199 }
200
201 return null;
202 }
203
204 /**
205 * Information relating to the currently installed MDM package manager.
206 */
207 public static final class MdmPackageInfo {
208 private final Drawable packageIcon;
209 private final String appLabel;
210
211 private MdmPackageInfo(Drawable packageIcon, String appLabel) {
212 this.packageIcon = packageIcon;
213 this.appLabel = appLabel;
214 }
215
216 public String getAppLabel() {
217 return appLabel;
218 }
219
220 public Drawable getPackageIcon() {
221 return packageIcon;
222 }
223 }
Joe Delfinod0f29282015-03-19 08:26:09 -0400224
225 public static boolean isCurrentUserOwner() {
226 return UserHandle.myUserId() == UserHandle.USER_OWNER;
227 }
Joe Delfino84e56f52015-03-27 09:56:18 -0400228
229 public static boolean hasDeviceOwner(Context context) {
230 DevicePolicyManager dpm =
231 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
232 return !TextUtils.isEmpty(dpm.getDeviceOwner());
233 }
234
235 public static boolean isManagedProfile(Context context) {
236 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
237 UserInfo user = um.getUserInfo(UserHandle.myUserId());
238 return user != null ? user.isManagedProfile() : false;
239 }
240
Sander Alewijnse74d6c142015-04-13 11:51:19 +0100241 /**
242 * Returns true if the given package does not exist on the device or if its version code is less
243 * than the given version, and false otherwise.
244 */
245 public static boolean packageRequiresUpdate(String packageName, int minSupportedVersion,
246 Context context) {
247 try {
248 PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
249 if (packageInfo.versionCode >= minSupportedVersion) {
250 return false;
251 }
252 } catch (NameNotFoundException e) {
253 // Package not on device.
254 }
255
256 return true;
257 }
258
Sander Alewijnse3efa83a2015-04-14 14:46:18 +0100259 public static byte[] stringToByteArray(String s)
260 throws NumberFormatException {
261 try {
262 return Base64.decode(s, Base64.URL_SAFE);
263 } catch (IllegalArgumentException e) {
264 throw new NumberFormatException("Incorrect format. Should be Url-safe Base64 encoded.");
265 }
266 }
267
268 public static String byteArrayToString(byte[] bytes) {
269 return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
270 }
Sander Alewijnsed5e4c422014-11-25 17:56:16 +0000271}