• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.app.DownloadManager;
19 import android.content.Context;
20 import android.content.pm.IPackageInstallObserver;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.PackageInfo;
23 import android.content.pm.PackageManager;
24 import android.net.Uri;
25 import android.provider.Settings.Global;
26 import android.text.TextUtils;
27 import android.Manifest.permission;
28 
29 import com.android.managedprovisioning.ProvisionLogger;
30 
31 import 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  */
40 public 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 
InstallPackageTask(Context context, String packageName, Callback callback)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 
run(String packageLocation)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 
packageContentIsCorrect()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
packageInstalled(String packageName, int returnCode)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 {
onSuccess()145         public abstract void onSuccess();
onError(int errorCode)146         public abstract void onError(int errorCode);
147     }
148 }