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 */ 16 package com.android.managedprovisioning.task; 17 18 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_INSTALL_PACKAGE_TASK_MS; 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.content.Context; 22 import android.content.pm.IPackageInstallObserver; 23 import android.content.pm.PackageManager; 24 import android.net.Uri; 25 import android.text.TextUtils; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.managedprovisioning.common.ProvisionLogger; 29 import com.android.managedprovisioning.R; 30 import com.android.managedprovisioning.common.SettingsFacade; 31 import com.android.managedprovisioning.model.ProvisioningParams; 32 33 import java.io.File; 34 35 /** 36 * Installs the management app apk from a download location provided by 37 * {@link DownloadPackageTask#getDownloadedPackageLocation()}. 38 */ 39 public class InstallPackageTask extends AbstractProvisioningTask { 40 public static final int ERROR_PACKAGE_INVALID = 0; 41 public static final int ERROR_INSTALLATION_FAILED = 1; 42 43 private final SettingsFacade mSettingsFacade; 44 private final DownloadPackageTask mDownloadPackageTask; 45 46 private PackageManager mPm; 47 private boolean mInitialPackageVerifierEnabled; 48 49 /** 50 * Create an InstallPackageTask. When run, this will attempt to install the device admin package 51 * if it is non-null. 52 * 53 * {@see #run(String, String)} for more detail on package installation. 54 */ InstallPackageTask( DownloadPackageTask downloadPackageTask, Context context, ProvisioningParams params, Callback callback)55 public InstallPackageTask( 56 DownloadPackageTask downloadPackageTask, 57 Context context, 58 ProvisioningParams params, 59 Callback callback) { 60 this(new SettingsFacade(), downloadPackageTask, context, params, callback); 61 } 62 63 @VisibleForTesting InstallPackageTask( SettingsFacade settingsFacade, DownloadPackageTask downloadPackageTask, Context context, ProvisioningParams params, Callback callback)64 InstallPackageTask( 65 SettingsFacade settingsFacade, 66 DownloadPackageTask downloadPackageTask, 67 Context context, 68 ProvisioningParams params, 69 Callback callback) { 70 super(context, params, callback); 71 72 mPm = context.getPackageManager(); 73 mSettingsFacade = checkNotNull(settingsFacade); 74 mDownloadPackageTask = checkNotNull(downloadPackageTask); 75 } 76 77 @Override getStatusMsgId()78 public int getStatusMsgId() { 79 return R.string.progress_install; 80 } 81 82 /** 83 * Installs a package. The package will be installed from the given location if one is provided. 84 * If a null or empty location is provided, and the package is installed for a different user, 85 * it will be enabled for the calling user. If the package location is not provided and the 86 * package is not installed for any other users, this task will produce an error. 87 * 88 * Errors will be indicated if a downloaded package is invalid, or installation fails. 89 */ 90 @Override run(int userId)91 public void run(int userId) { 92 startTaskTimer(); 93 String packageLocation = mDownloadPackageTask.getDownloadedPackageLocation(); 94 String packageName = mProvisioningParams.inferDeviceAdminPackageName(); 95 96 ProvisionLogger.logi("Installing package"); 97 mInitialPackageVerifierEnabled = mSettingsFacade.isPackageVerifierEnabled(mContext); 98 if (TextUtils.isEmpty(packageLocation)) { 99 // Do not log time if not installing any package, as that isn't useful. 100 success(); 101 return; 102 } 103 104 // Temporarily turn off package verification. 105 mSettingsFacade.setPackageVerifierEnabled(mContext, false); 106 107 // Allow for replacing an existing package. 108 // Needed in case this task is performed multiple times. 109 mPm.installPackage(Uri.parse("file://" + packageLocation), 110 new PackageInstallObserver(packageName, packageLocation), 111 /* flags */ PackageManager.INSTALL_REPLACE_EXISTING, 112 mContext.getPackageName()); 113 } 114 115 @Override getMetricsCategory()116 protected int getMetricsCategory() { 117 return PROVISIONING_INSTALL_PACKAGE_TASK_MS; 118 } 119 120 private class PackageInstallObserver extends IPackageInstallObserver.Stub { 121 private final String mPackageName; 122 private final String mPackageLocation; 123 PackageInstallObserver(String packageName, String packageLocation)124 public PackageInstallObserver(String packageName, String packageLocation) { 125 mPackageName = packageName; 126 mPackageLocation = packageLocation; 127 } 128 129 @Override packageInstalled(String packageName, int returnCode)130 public void packageInstalled(String packageName, int returnCode) { 131 mSettingsFacade.setPackageVerifierEnabled(mContext, mInitialPackageVerifierEnabled); 132 if (packageName != null && !packageName.equals(mPackageName)) { 133 ProvisionLogger.loge("Package doesn't have expected package name."); 134 error(ERROR_PACKAGE_INVALID); 135 return; 136 } 137 if (returnCode == PackageManager.INSTALL_SUCCEEDED) { 138 ProvisionLogger.logd("Package " + mPackageName + " is succesfully installed."); 139 stopTaskTimer(); 140 success(); 141 } else if (returnCode == PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE) { 142 ProvisionLogger.logd("Current version of " + mPackageName 143 + " higher than the version to be installed. It was not reinstalled."); 144 // If the package is already at a higher version: success. 145 // Do not log time if package is already at a higher version, as that isn't useful. 146 success(); 147 } else { 148 ProvisionLogger.logd( 149 "Installing package " + mPackageName + " failed."); 150 ProvisionLogger.logd( 151 "Errorcode returned by IPackageInstallObserver = " + returnCode); 152 error(ERROR_INSTALLATION_FAILED); 153 } 154 // remove the file containing the apk in order not to use too much space. 155 new File(mPackageLocation).delete(); 156 } 157 } 158 } 159