| /* |
| * Copyright 2014, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.managedprovisioning; |
| |
| import android.app.admin.DevicePolicyManager; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.IPackageManager; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.content.pm.UserInfo; |
| import android.graphics.drawable.Drawable; |
| import android.os.Binder; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.text.TextUtils; |
| import android.util.Base64; |
| |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; |
| import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; |
| |
| /** |
| * Class containing various auxiliary methods. |
| */ |
| public class Utils { |
| private Utils() {} |
| |
| public static Set<String> getCurrentSystemApps(int userId) { |
| IPackageManager ipm = IPackageManager.Stub.asInterface(ServiceManager |
| .getService("package")); |
| Set<String> apps = new HashSet<String>(); |
| List<ApplicationInfo> aInfos = null; |
| try { |
| aInfos = ipm.getInstalledApplications( |
| PackageManager.GET_UNINSTALLED_PACKAGES, userId).getList(); |
| } catch (RemoteException neverThrown) { |
| ProvisionLogger.loge("This should not happen.", neverThrown); |
| } |
| for (ApplicationInfo aInfo : aInfos) { |
| if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { |
| apps.add(aInfo.packageName); |
| } |
| } |
| return apps; |
| } |
| |
| public static void disableComponent(ComponentName toDisable, int userId) { |
| try { |
| IPackageManager ipm = IPackageManager.Stub.asInterface(ServiceManager |
| .getService("package")); |
| |
| ipm.setComponentEnabledSetting(toDisable, |
| PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP, |
| userId); |
| } catch (RemoteException neverThrown) { |
| ProvisionLogger.loge("This should not happen.", neverThrown); |
| } catch (Exception e) { |
| ProvisionLogger.logw("Component not found, not disabling it: " |
| + toDisable.toShortString()); |
| } |
| } |
| |
| public static ComponentName findDeviceAdminFromIntent(Intent intent, Context c) |
| throws IllegalProvisioningArgumentException { |
| ComponentName mdmComponentName = intent.getParcelableExtra( |
| EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); |
| String mdmPackageName = intent.getStringExtra( |
| EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME); |
| return findDeviceAdmin(mdmPackageName, mdmComponentName, c); |
| } |
| |
| /** |
| * Exception thrown when the provisioning has failed completely. |
| * |
| * We're using a custom exception to avoid catching subsequent exceptions that might be |
| * significant. |
| */ |
| public static class IllegalProvisioningArgumentException extends Exception { |
| public IllegalProvisioningArgumentException(String message) { |
| super(message); |
| } |
| |
| public IllegalProvisioningArgumentException(String message, Throwable t) { |
| super(message, t); |
| } |
| } |
| |
| /** |
| * Check the validity of the admin component name supplied, or try to infer this componentName |
| * from the package. |
| * |
| * We are supporting lookup by package name for legacy reasons. |
| * |
| * If mdmComponentName is supplied (not null): |
| * mdmPackageName is ignored. |
| * Check that the package of mdmComponentName is installed, that mdmComponentName is a |
| * receiver in this package, and return it. |
| * |
| * Otherwise: |
| * mdmPackageName must be supplied (not null). |
| * Check that this package is installed, try to infer a potential device admin in this package, |
| * and return it. |
| */ |
| public static ComponentName findDeviceAdmin(String mdmPackageName, |
| ComponentName mdmComponentName, Context c) throws IllegalProvisioningArgumentException { |
| if (mdmComponentName != null) { |
| mdmPackageName = mdmComponentName.getPackageName(); |
| } |
| if (mdmPackageName == null) { |
| throw new IllegalProvisioningArgumentException("Neither the package name nor the" |
| + " component name of the admin are supplied"); |
| } |
| PackageInfo pi; |
| try { |
| pi = c.getPackageManager().getPackageInfo(mdmPackageName, |
| PackageManager.GET_RECEIVERS); |
| } catch (NameNotFoundException e) { |
| throw new IllegalProvisioningArgumentException("Mdm "+ mdmPackageName |
| + " is not installed. ", e); |
| } |
| if (mdmComponentName != null) { |
| // If the component was specified in the intent: check that it is in the manifest. |
| checkAdminComponent(mdmComponentName, pi); |
| return mdmComponentName; |
| } else { |
| // Otherwise: try to find a potential device admin in the manifest. |
| return findDeviceAdminInPackage(mdmPackageName, pi); |
| } |
| } |
| |
| private static void checkAdminComponent(ComponentName mdmComponentName, PackageInfo pi) |
| throws IllegalProvisioningArgumentException{ |
| for (ActivityInfo ai : pi.receivers) { |
| if (mdmComponentName.getClassName().equals(ai.name)) { |
| return; |
| } |
| } |
| throw new IllegalProvisioningArgumentException("The component " + mdmComponentName |
| + " cannot be found"); |
| } |
| |
| private static ComponentName findDeviceAdminInPackage(String mdmPackageName, PackageInfo pi) |
| throws IllegalProvisioningArgumentException { |
| ComponentName mdmComponentName = null; |
| for (ActivityInfo ai : pi.receivers) { |
| if (!TextUtils.isEmpty(ai.permission) && |
| ai.permission.equals(android.Manifest.permission.BIND_DEVICE_ADMIN)) { |
| if (mdmComponentName != null) { |
| throw new IllegalProvisioningArgumentException("There are several " |
| + "device admins in " + mdmPackageName + " but no one in specified"); |
| } else { |
| mdmComponentName = new ComponentName(mdmPackageName, ai.name); |
| } |
| } |
| } |
| if (mdmComponentName == null) { |
| throw new IllegalProvisioningArgumentException("There are no device admins in" |
| + mdmPackageName); |
| } |
| return mdmComponentName; |
| } |
| |
| public static MdmPackageInfo getMdmPackageInfo(PackageManager pm, String packageName) { |
| if (packageName != null) { |
| try { |
| ApplicationInfo ai = pm.getApplicationInfo(packageName, /* default flags */ 0); |
| if (ai != null) { |
| return new MdmPackageInfo(pm.getApplicationIcon(packageName), |
| pm.getApplicationLabel(ai).toString()); |
| } |
| } catch (PackageManager.NameNotFoundException e) { |
| // Package does not exist, ignore. Should never happen. |
| ProvisionLogger.loge("Package does not exist. Should never happen."); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Information relating to the currently installed MDM package manager. |
| */ |
| public static final class MdmPackageInfo { |
| private final Drawable packageIcon; |
| private final String appLabel; |
| |
| private MdmPackageInfo(Drawable packageIcon, String appLabel) { |
| this.packageIcon = packageIcon; |
| this.appLabel = appLabel; |
| } |
| |
| public String getAppLabel() { |
| return appLabel; |
| } |
| |
| public Drawable getPackageIcon() { |
| return packageIcon; |
| } |
| } |
| |
| public static boolean isCurrentUserOwner() { |
| return UserHandle.myUserId() == UserHandle.USER_OWNER; |
| } |
| |
| public static boolean hasDeviceOwner(Context context) { |
| DevicePolicyManager dpm = |
| (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); |
| return !TextUtils.isEmpty(dpm.getDeviceOwner()); |
| } |
| |
| public static boolean isManagedProfile(Context context) { |
| UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); |
| UserInfo user = um.getUserInfo(UserHandle.myUserId()); |
| return user != null ? user.isManagedProfile() : false; |
| } |
| |
| /** |
| * Returns true if the given package does not exist on the device or if its version code is less |
| * than the given version, and false otherwise. |
| */ |
| public static boolean packageRequiresUpdate(String packageName, int minSupportedVersion, |
| Context context) { |
| try { |
| PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); |
| if (packageInfo.versionCode >= minSupportedVersion) { |
| return false; |
| } |
| } catch (NameNotFoundException e) { |
| // Package not on device. |
| } |
| |
| return true; |
| } |
| |
| public static byte[] stringToByteArray(String s) |
| throws NumberFormatException { |
| try { |
| return Base64.decode(s, Base64.URL_SAFE); |
| } catch (IllegalArgumentException e) { |
| throw new NumberFormatException("Incorrect format. Should be Url-safe Base64 encoded."); |
| } |
| } |
| |
| public static String byteArrayToString(byte[] bytes) { |
| return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); |
| } |
| } |