PacakgeManagerService学习笔记八-APK installation

来源:互联网 发布:mac只安装win10 编辑:程序博客网 时间:2024/05/17 08:37

<----接上---->

/*DefaultContainerService.java*/

1. getMinimalPackageInfo: 获取一个PackageInfoLite对象

public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) {            PackageInfoLite ret = new PackageInfoLite();            if (fileUri == null) {                Slog.i(TAG, "Invalid package uri " + fileUri);                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;                return ret;            }            String scheme = fileUri.getScheme();            if (scheme != null && !scheme.equals("file")) {                Slog.w(TAG, "Falling back to installing on internal storage only");                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL;                return ret;            }            String archiveFilePath = fileUri.getPath();            DisplayMetrics metrics = new DisplayMetrics();            metrics.setToDefaults();/*解析该APK*/            PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0);            if (pkg == null) {                Slog.w(TAG, "Failed to parse package");                final File apkFile = new File(archiveFilePath);                if (!apkFile.exists()) {                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;                } else {                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;                }                return ret;            }            ret.packageName = pkg.packageName;            ret.installLocation = pkg.installLocation;            ret.verifiers = pkg.verifiers;/*取得一个合理的安装位置*/            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,                    archiveFilePath, flags, threshold);            return ret;        }
2. recommandedAppInstallLocation: 获取一个合理的安装位置

1> 当APK的AndroidManifest.xml中设置的位置为AUTO,在具体对应时倾向内部存储空间

2> 用户在Settings数据库中设置的安装位置

3> 检查外部存储或者内部存储是否有足够的空间

private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags,            long threshold) {        int prefer;        boolean checkBoth = false;        check_inner : {            /*             * Explicit install flags should override the manifest settings.             */            if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {                /*                 * Forward-locked applications cannot be installed on SD card,                 * so only allow checking internal storage.                 */                prefer = PREFER_INTERNAL;                break check_inner;            } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) {                prefer = PREFER_INTERNAL;                break check_inner;            } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {                prefer = PREFER_EXTERNAL;                break check_inner;            }            /* No install flags. Check for manifest option. */            if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {                prefer = PREFER_INTERNAL;                break check_inner;            } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {                prefer = PREFER_EXTERNAL;                checkBoth = true;                break check_inner;            } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {                // We default to preferring internal storage.                prefer = PREFER_INTERNAL;                checkBoth = true;                break check_inner;            }            // Pick user preference            int installPreference = Settings.System.getInt(getApplicationContext()                    .getContentResolver(),                    Settings.Secure.DEFAULT_INSTALL_LOCATION,                    PackageHelper.APP_INSTALL_AUTO);            if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {                prefer = PREFER_INTERNAL;                break check_inner;            } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {                prefer = PREFER_EXTERNAL;                break check_inner;            }            /*             * Fall back to default policy of internal-only if nothing else is             * specified.             */            prefer = PREFER_INTERNAL;        }        final boolean emulated = Environment.isExternalStorageEmulated();        final File apkFile = new File(archiveFilePath);        boolean fitsOnInternal = false;        if (checkBoth || prefer == PREFER_INTERNAL) {            try {                fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);            } catch (FileNotFoundException e) {                return PackageHelper.RECOMMEND_FAILED_INVALID_URI;            }        }        boolean fitsOnSd = false;        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {            try {                fitsOnSd = isUnderExternalThreshold(apkFile);            } catch (FileNotFoundException e) {                return PackageHelper.RECOMMEND_FAILED_INVALID_URI;            }        }        if (prefer == PREFER_INTERNAL) {            if (fitsOnInternal) {                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;            }        } else if (!emulated && prefer == PREFER_EXTERNAL) {            if (fitsOnSd) {                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;            }        }        if (checkBoth) {            if (fitsOnInternal) {                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;            } else if (!emulated && fitsOnSd) {                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;            }        }        /*         * If they requested to be on the external media by default, return that         * the media was unavailable. Otherwise, indicate there was insufficient         * storage space available.         */        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)                && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {            return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;        } else {            return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;        }    }
经过以上步骤,会得到一个合理的安装位置,下面开始复制文件:

3. InstallArgs的copyAPK方法

1> /data/app/创建一个临时文件,临时文件名为vmdl-随机数.tmp, 用这样的文件名是防止触发PKMS扫描启动。PKMS通过inotify机制监控了文件系统。

 int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {            if (temp) {                // Generate temp file name                createCopyFile();            }            // Get a ParcelFileDescriptor to write to the output file            File codeFile = new File(codeFileName);            if (!created) {                try {                    codeFile.createNewFile();                    // Set permissions                    if (!setPermissions()) {                        // Failed setting permissions.                        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;                    }                } catch (IOException e) {                   Slog.w(TAG, "Failed to create file " + codeFile);                   return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;                }            }            ParcelFileDescriptor out = null;            try {                out = ParcelFileDescriptor.open(codeFile, ParcelFileDescriptor.MODE_READ_WRITE);            } catch (FileNotFoundException e) {                Slog.e(TAG, "Failed to create file descriptor for : " + codeFileName);                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;            }            // Copy the resource now            int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;            try {                mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,                        Intent.FLAG_GRANT_READ_URI_PERMISSION);                ret = imcs.copyResource(packageURI, out);            } finally {                try { if (out != null) out.close(); } catch (IOException e) {}                mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);            }            return ret;        }

4. handleReturnCode: handleStartCopy执行完后会调用该方法

        void handleReturnCode() {            // If mArgs is null, then MCS couldn't be reached. When it            // reconnects, it will try again to install. At that point, this            // will succeed.            if (mArgs != null) {                processPendingInstall(mArgs, mRet);            }        }
5. processPendingInstall主要完成的工作:

1> 调用InstallArgs的doPreInstall方法; 

2> 调用installPackageLI方法进行APK安装,该方法内部将调用doRename方法对临时文件改名,另外,还需要扫描此APK文件,将此APK信息加入到PKMS的成员中

3> 调用InstallArgs的doPostInstall方法

4> APK安装完成,向mHandler发送POST_INSTALL消息,该消息标记一个token,通过它可以从mRunningInstalls数组中取得一个PostInstallData对象

private void processPendingInstall(final InstallArgs args, final int currentStatus) {        // Queue up an async operation since the package installation may take a little while.        mHandler.post(new Runnable() {            public void run() {                mHandler.removeCallbacks(this);                 // Result object to be returned/*创建一个PackageInstalledInfo对象*/                PackageInstalledInfo res = new PackageInstalledInfo();                res.returnCode = currentStatus;                res.uid = -1;                res.pkg = null;                res.removedInfo = new PackageRemovedInfo();                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {/*调用FileInstallArgs的doPreInstall*/                    args.doPreInstall(res.returnCode);                    synchronized (mInstallLock) {/*调用installPackageLI进行安装*/                        installPackageLI(args, true, res);                    }/*调用FileInstallArgs的doPostInstall*/                    args.doPostInstall(res.returnCode);                }                // A restore should be performed at this point if (a) the install                // succeeded, (b) the operation is not an update, and (c) the new                // package has a backupAgent defined.                final boolean update = res.removedInfo.removedPackage != null;                boolean doRestore = (!update                        && res.pkg != null                        && res.pkg.applicationInfo.backupAgentName != null);                // Set up the post-install work request bookkeeping.  This will be used                // and cleaned up by the post-install event handling regardless of whether                // there's a restore pass performed.  Token values are >= 1.                int token;                if (mNextInstallToken < 0) mNextInstallToken = 1;                token = mNextInstallToken++;                PostInstallData data = new PostInstallData(args, res);/*保存对象到mRunningInstalls*/                mRunningInstalls.put(token, data);                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {                    // Pass responsibility to the Backup Manager.  It will perform a                    // restore if appropriate, then pass responsibility back to the                    // Package Manager to run the post-install observer callbacks                    // and broadcasts.                    IBackupManager bm = IBackupManager.Stub.asInterface(                            ServiceManager.getService(Context.BACKUP_SERVICE));                    if (bm != null) {                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token                                + " to BM for possible restore");                        try {                            bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);                        } catch (RemoteException e) {                            // can't happen; the backup manager is local                        } catch (Exception e) {                            Slog.e(TAG, "Exception trying to enqueue restore", e);                            doRestore = false;                        }                    } else {                        Slog.e(TAG, "Backup Manager not found!");                        doRestore = false;                    }                }                if (!doRestore) {                    // No restore possible, or the Backup Manager was mysteriously not                    // available -- just fire the post-install work request directly.                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);/*发一个消息给mHandler*/                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);                    mHandler.sendMessage(msg);                }            }        });    }

6. POST_INSTALL

/*省略*/case POST_INSTALL: {                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);                    PostInstallData data = mRunningInstalls.get(msg.arg1);                    mRunningInstalls.delete(msg.arg1);                    boolean deleteOld = false;                    if (data != null) {                        InstallArgs args = data.args;                        PackageInstalledInfo res = data.res;                        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {                            res.removedInfo.sendBroadcast(false, true);                            Bundle extras = new Bundle(1);                            extras.putInt(Intent.EXTRA_UID, res.uid);                            final boolean update = res.removedInfo.removedPackage != null;                            if (update) {                                extras.putBoolean(Intent.EXTRA_REPLACING, true);                            }/*发送PACKAGE_ADDED广播*/                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,                                    res.pkg.applicationInfo.packageName,                                    extras, null, null);                            if (update) {                                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,                                        res.pkg.applicationInfo.packageName,                                        extras, null, null);                                sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,                                        null, null,                                        res.pkg.applicationInfo.packageName, null);                            }                            if (res.removedInfo.args != null) {                                // Remove the replaced package's older resources safely now                                deleteOld = true;                            }                        }                        // Force a gc to clear up things                        Runtime.getRuntime().gc();                        // We delete after a gc for applications  on sdcard.                        if (deleteOld) {                            synchronized (mInstallLock) {                                res.removedInfo.args.doPostDeleteLI(true);                            }                        }                        if (args.observer != null) {                            try {/*通知pm安装结果*/                                args.observer.packageInstalled(res.name, res.returnCode);                            } catch (RemoteException e) {                                Slog.i(TAG, "Observer no longer exists.");                            }                        }                    } else {                        Slog.e(TAG, "Bogus post-install token " + msg.arg1);                    }                } break;/*省略*/
至此,APK安装完成。



0 0
原创粉丝点击