14c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse/*
24c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * Copyright 2014, The Android Open Source Project
34c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse *
44c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * Licensed under the Apache License, Version 2.0 (the "License");
54c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * you may not use this file except in compliance with the License.
64c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * You may obtain a copy of the License at
74c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse *
84c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse *      http://www.apache.org/licenses/LICENSE-2.0
94c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse *
104c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * Unless required by applicable law or agreed to in writing, software
114c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * distributed under the License is distributed on an "AS IS" BASIS,
124c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * See the License for the specific language governing permissions and
144c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * limitations under the License.
154c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse */
164c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnsepackage com.android.managedprovisioning.task;
174c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
184c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.app.DownloadManager;
194c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.content.Context;
204c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.content.pm.IPackageInstallObserver;
214c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.content.pm.ActivityInfo;
224c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.content.pm.PackageInfo;
234c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.content.pm.PackageManager;
244c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.net.Uri;
250080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnseimport android.provider.Settings.Global;
264c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.text.TextUtils;
274c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport android.Manifest.permission;
284c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
294c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport com.android.managedprovisioning.ProvisionLogger;
304c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
314c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnseimport java.io.File;
324c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
334c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse/**
344c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * Installs a device owner package from a given path.
354c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * <p>
364c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * Before installing it is checked whether the file at the specified path contains the given package
374c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * and the given admin receiver.
384c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse * </p>
394c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse */
404c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnsepublic class InstallPackageTask {
414c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    public static final int ERROR_PACKAGE_INVALID = 0;
424c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    public static final int ERROR_INSTALLATION_FAILED = 1;
434c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
4428bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse    private final Context mContext;
4528bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse    private final Callback mCallback;
4628bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse    private final String mPackageName;
4728bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse
484c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    private String mPackageLocation;
494c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    private PackageManager mPm;
500080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse    private int mPackageVerifierEnable;
514c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
52cdf13b1826bd84f7d5c11ba14d14eb4889c2dda8Sander Alewijnse    public InstallPackageTask (Context context, String packageName,
5328bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse            Callback callback) {
5428bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse        mCallback = callback;
554c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        mContext = context;
564c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        mPackageLocation = null; // Initialized in run().
574c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        mPackageName = packageName;
584c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    }
594c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
60d70438542632a1c8df15bdd9d91bfee52bf2b655Sander Alewijnse    public void run(String packageLocation) {
614c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        if (TextUtils.isEmpty(packageLocation)) {
624c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            ProvisionLogger.loge("Package Location is empty.");
634c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            mCallback.onError(ERROR_PACKAGE_INVALID);
644c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            return;
654c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        }
664c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        mPackageLocation = packageLocation;
674c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
684c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        PackageInstallObserver observer = new PackageInstallObserver();
694c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        mPm = mContext.getPackageManager();
704c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
714c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        if (packageContentIsCorrect()) {
72bdd8d3f865e51915fb11776d21ac2fb2888e0f22Sander Alewijnse            // Temporarily turn off package verification.
730080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse            mPackageVerifierEnable = Global.getInt(mContext.getContentResolver(),
740080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse                    Global.PACKAGE_VERIFIER_ENABLE, 1);
750080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse            Global.putInt(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_ENABLE, 0);
760080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse
778c664076cc8e08985c58e9da8d85ab162c9533efSander Alewijnse            Uri packageUri = Uri.parse("file://" + mPackageLocation);
788c664076cc8e08985c58e9da8d85ab162c9533efSander Alewijnse
794c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            // Allow for replacing an existing package.
804c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            // Needed in case this task is performed multiple times.
818c664076cc8e08985c58e9da8d85ab162c9533efSander Alewijnse            mPm.installPackage(packageUri, observer,
824c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                    /* flags */ PackageManager.INSTALL_REPLACE_EXISTING, mContext.getPackageName());
834c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        } else {
844c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            // Error should have been reported in packageContentIsCorrect().
854c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            return;
864c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        }
874c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    }
884c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
894c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    private boolean packageContentIsCorrect() {
904c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        PackageInfo pi = mPm.getPackageArchiveInfo(mPackageLocation,
914c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                PackageManager.GET_RECEIVERS);
924c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        if (pi == null) {
934c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            ProvisionLogger.loge("Package could not be parsed successfully.");
944c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            mCallback.onError(ERROR_PACKAGE_INVALID);
954c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            return false;
964c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        }
974c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        if (!pi.packageName.equals(mPackageName)) {
984c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            ProvisionLogger.loge("Package name in apk (" + pi.packageName
994c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                    + ") does not match package name specified by programmer ("
1004c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                    + mPackageName + ").");
1014c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            mCallback.onError(ERROR_PACKAGE_INVALID);
1024c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            return false;
1034c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        }
1044c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        for (ActivityInfo ai : pi.receivers) {
1054c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            if (!TextUtils.isEmpty(ai.permission) &&
1064c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                    ai.permission.equals(android.Manifest.permission.BIND_DEVICE_ADMIN)) {
107cdf13b1826bd84f7d5c11ba14d14eb4889c2dda8Sander Alewijnse                return true;
1084c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            }
1094c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        }
1104c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        ProvisionLogger.loge("Installed package has no admin receiver.");
1114c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        mCallback.onError(ERROR_PACKAGE_INVALID);
1124c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        return false;
1134c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    }
1144c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
1154c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    private class PackageInstallObserver extends IPackageInstallObserver.Stub {
1164c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        @Override
1174c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        public void packageInstalled(String packageName, int returnCode) {
118bdd8d3f865e51915fb11776d21ac2fb2888e0f22Sander Alewijnse            // Set package verification flag to its original value.
1190080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse            Global.putInt(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_ENABLE,
1200080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse                    mPackageVerifierEnable);
1210080f2afbafe0ed837bb2778a7a36357a0c42946Sander Alewijnse
12223d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse            if (returnCode == PackageManager.INSTALL_SUCCEEDED
12323d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                    && mPackageName.equals(packageName)) {
12423d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                ProvisionLogger.logd("Package " + mPackageName + " is succesfully installed.");
125d70438542632a1c8df15bdd9d91bfee52bf2b655Sander Alewijnse
1264c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                mCallback.onSuccess();
1274c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            } else {
12823d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                if (returnCode == PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE) {
12923d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                    ProvisionLogger.logd("Current version of " + mPackageName
13023d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                            + " higher than the version to be installed.");
13123d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                    ProvisionLogger.logd("Package " + mPackageName + " was not reinstalled.");
13223d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                    mCallback.onSuccess();
13323d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                    return;
13423d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                }
13523d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse
13623d457375fbcb1488b7b5d5e5c0d7a4cca78c77bSander Alewijnse                ProvisionLogger.logd("Installing package " + mPackageName + " failed.");
1374c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                ProvisionLogger.logd("Errorcode returned by IPackageInstallObserver = "
1384c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                        + returnCode);
1394c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse                mCallback.onError(ERROR_INSTALLATION_FAILED);
1404c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse            }
1414c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        }
1424c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    }
1434c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse
1444c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    public abstract static class Callback {
1454c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        public abstract void onSuccess();
1464c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse        public abstract void onError(int errorCode);
1474c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse    }
1484c4badfbd6a9271297c12a7db495ca2e7bd7734dSander Alewijnse}