1/* 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 */ 16package com.android.managedprovisioning.task; 17 18import android.app.DownloadManager; 19import android.content.Context; 20import android.content.pm.IPackageInstallObserver; 21import android.content.pm.ActivityInfo; 22import android.content.pm.PackageInfo; 23import android.content.pm.PackageManager; 24import android.net.Uri; 25import android.provider.Settings.Global; 26import android.text.TextUtils; 27import android.Manifest.permission; 28 29import com.android.managedprovisioning.ProvisionLogger; 30 31import java.io.File; 32 33/** 34 * Installs a device owner package from a given path. 35 * <p> 36 * Before installing it is checked whether the file at the specified path contains the given package 37 * and the given admin receiver. 38 * </p> 39 */ 40public class InstallPackageTask { 41 public static final int ERROR_PACKAGE_INVALID = 0; 42 public static final int ERROR_INSTALLATION_FAILED = 1; 43 44 private final Context mContext; 45 private final Callback mCallback; 46 private final String mPackageName; 47 48 private String mPackageLocation; 49 private PackageManager mPm; 50 private int mPackageVerifierEnable; 51 52 public InstallPackageTask (Context context, String packageName, 53 Callback callback) { 54 mCallback = callback; 55 mContext = context; 56 mPackageLocation = null; // Initialized in run(). 57 mPackageName = packageName; 58 } 59 60 public void run(String packageLocation) { 61 if (TextUtils.isEmpty(packageLocation)) { 62 ProvisionLogger.loge("Package Location is empty."); 63 mCallback.onError(ERROR_PACKAGE_INVALID); 64 return; 65 } 66 mPackageLocation = packageLocation; 67 68 PackageInstallObserver observer = new PackageInstallObserver(); 69 mPm = mContext.getPackageManager(); 70 71 if (packageContentIsCorrect()) { 72 // Temporarily turn off package verification. 73 mPackageVerifierEnable = Global.getInt(mContext.getContentResolver(), 74 Global.PACKAGE_VERIFIER_ENABLE, 1); 75 Global.putInt(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_ENABLE, 0); 76 77 Uri packageUri = Uri.parse("file://" + mPackageLocation); 78 79 // Allow for replacing an existing package. 80 // Needed in case this task is performed multiple times. 81 mPm.installPackage(packageUri, observer, 82 /* flags */ PackageManager.INSTALL_REPLACE_EXISTING, mContext.getPackageName()); 83 } else { 84 // Error should have been reported in packageContentIsCorrect(). 85 return; 86 } 87 } 88 89 private boolean packageContentIsCorrect() { 90 PackageInfo pi = mPm.getPackageArchiveInfo(mPackageLocation, 91 PackageManager.GET_RECEIVERS); 92 if (pi == null) { 93 ProvisionLogger.loge("Package could not be parsed successfully."); 94 mCallback.onError(ERROR_PACKAGE_INVALID); 95 return false; 96 } 97 if (!pi.packageName.equals(mPackageName)) { 98 ProvisionLogger.loge("Package name in apk (" + pi.packageName 99 + ") does not match package name specified by programmer (" 100 + mPackageName + ")."); 101 mCallback.onError(ERROR_PACKAGE_INVALID); 102 return false; 103 } 104 for (ActivityInfo ai : pi.receivers) { 105 if (!TextUtils.isEmpty(ai.permission) && 106 ai.permission.equals(android.Manifest.permission.BIND_DEVICE_ADMIN)) { 107 return true; 108 } 109 } 110 ProvisionLogger.loge("Installed package has no admin receiver."); 111 mCallback.onError(ERROR_PACKAGE_INVALID); 112 return false; 113 } 114 115 private class PackageInstallObserver extends IPackageInstallObserver.Stub { 116 @Override 117 public void packageInstalled(String packageName, int returnCode) { 118 // Set package verification flag to its original value. 119 Global.putInt(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_ENABLE, 120 mPackageVerifierEnable); 121 122 if (returnCode == PackageManager.INSTALL_SUCCEEDED 123 && mPackageName.equals(packageName)) { 124 ProvisionLogger.logd("Package " + mPackageName + " is succesfully installed."); 125 126 mCallback.onSuccess(); 127 } else { 128 if (returnCode == PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE) { 129 ProvisionLogger.logd("Current version of " + mPackageName 130 + " higher than the version to be installed."); 131 ProvisionLogger.logd("Package " + mPackageName + " was not reinstalled."); 132 mCallback.onSuccess(); 133 return; 134 } 135 136 ProvisionLogger.logd("Installing package " + mPackageName + " failed."); 137 ProvisionLogger.logd("Errorcode returned by IPackageInstallObserver = " 138 + returnCode); 139 mCallback.onError(ERROR_INSTALLATION_FAILED); 140 } 141 } 142 } 143 144 public abstract static class Callback { 145 public abstract void onSuccess(); 146 public abstract void onError(int errorCode); 147 } 148}