文档章节

Android应用程序安装和显示

会飞的章鱼
 会飞的章鱼
发布于 2015/06/25 16:51
字数 1489
阅读 12
收藏 0

在Android启动的过程中,会扫描系统中特定的目录,以便对保存在里面的应用程序进行安装,例如/system/app,/data/app。这个主要是靠PackageManagerService来实现,PackageManagerService在安装一个应用程序的过程中主要做两件事,1、解析这个应用程序的配置文件AndroidManifest.xml 以便获取安装信息,2、为这个应用程序分配Linux用户ID和Linux用户组ID,以便他可以运行在系统中获得权限

    Android系统中最后一步是启动一个HOME程序,用来显示系统中已经安装的应用程序,Android提供原声的程序是Launcher,应用程序在启动中,会请求PackageManagerService提供安装的应用程序信息,再将程序信息封装成一个快捷图标在屏幕中,这样用户就可以根据图标来启动对应的程序,

    PackageManagerService在安装一个应用程序的时候,对AndroidManifest.xml进行解析,获取到组件信息,Android系统的每一个应用程序都有一个Linux用户ID,这些ID是有PackageManagerService负责分配的,PackageManagerService在安装一个应用程序的时候,如果发现没有其他应用程序共享一个Linux用户ID,那么就会为它分配唯一的Linux用户ID,这样可以获得所需的权限,有了用户ID之外还有若干个Linux用户组ID,以便获得更多的资源,Linux用户组ID也是PackageManagerService来负责分配的,

在PackageManagerService.java中

public static final IPackageManager main(Context context, boolean factoryTest,
            boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
        ServiceManager.addService("package", m);
        return m;
    }

首先将PackageManagerService启动起来,然后注册到ServiceManager中,这样系统通过ServiceManager来获取安装服务。

 public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());
        if (mSdkVersion <= 0) {
            Slog.w(TAG, "**** ro.build.version.sdk not set!");
        }
        mContext = context;
        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
        mMetrics = new DisplayMetrics();
        mSettings = new Settings();
        mSettings.addSharedUserLPw("android.uid.system",
                Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.phone",
                MULTIPLE_APPLICATION_UIDS
                        ? RADIO_UID : FIRST_APPLICATION_UID,
                ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.log",
                MULTIPLE_APPLICATION_UIDS
                        ? LOG_UID : FIRST_APPLICATION_UID,
                ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.nfc",
                MULTIPLE_APPLICATION_UIDS
                        ? NFC_UID : FIRST_APPLICATION_UID,
                ApplicationInfo.FLAG_SYSTEM);

        String separateProcesses = SystemProperties.get("debug.separate_processes");
        if (separateProcesses != null && separateProcesses.length() > 0) {
            if ("*".equals(separateProcesses)) {
                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                mSeparateProcesses = null;
                Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
            } else {
                mDefParseFlags = 0;
                mSeparateProcesses = separateProcesses.split(",");
                Slog.w(TAG, "Running with debug.separate_processes: "
                        + separateProcesses);
            }
        } else {
            mDefParseFlags = 0;
            mSeparateProcesses = null;
        }

        mInstaller = new Installer();

        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Display d = wm.getDefaultDisplay();
        d.getMetrics(mMetrics);

        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());

            File dataDir = Environment.getDataDirectory();//获得系统的数据目录/data
            mAppDataDir = new File(dataDir, "data");
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");//获得的是/data/app-private目录,主要是受DRM保护的私有应用程序,/data/app下面是自己安装的应用程序。

            mUserManager = new UserManager(mInstaller, mUserAppDataDir);

            readPermissions();

            mRestoredSettings = mSettings.readLPw();//恢复上一次应用程序的安装信息,接下来就扫描和安装保存在特定目录的应用程序
            long startTime = SystemClock.uptimeMillis();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX;
            if (mNoDexOpt) {
                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                scanMode |= SCAN_NO_DEX;
            }

            final HashSet<String> libFiles = new HashSet<String>();

            mFrameworkDir = new File(Environment.getRootDirectory(), "framework");//获得的是/system/framework目录
            mDalvikCacheDir = new File(dataDir, "dalvik-cache");

            boolean didDexOpt = false;

            /**
             * Out of paranoia, ensure that everything in the boot class
             * path has been dexed.
             */
            String bootClassPath = System.getProperty("java.boot.class.path");
            if (bootClassPath != null) {
                String[] paths = splitString(bootClassPath, ':');
                for (int i=0; i<paths.length; i++) {
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
                            libFiles.add(paths[i]);
                            mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
                            didDexOpt = true;
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Boot class path not found: " + paths[i]);
                    } catch (IOException e) {
                        Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "
                                + e.getMessage());
                    }
                }
            } else {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            /**
             * Also ensure all external libraries have had dexopt run on them.
             */
            if (mSharedLibraries.size() > 0) {
                Iterator<String> libs = mSharedLibraries.values().iterator();
                while (libs.hasNext()) {
                    String lib = libs.next();
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
                            libFiles.add(lib);
                            mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
                            didDexOpt = true;
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Library not found: " + lib);
                    } catch (IOException e) {
                        Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                + e.getMessage());
                    }
                }
            }

            // Gross hack for now: we know this file doesn't contain any
            // code, so don't dexopt it to avoid the resulting log spew.
            libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");

            /**
             * And there are a number of commands implemented in Java, which
             * we currently need to do the dexopt on so that they can be
             * run from a non-root shell.
             */
            String[] frameworkFiles = mFrameworkDir.list();
            if (frameworkFiles != null) {
                for (int i=0; i<frameworkFiles.length; i++) {
                    File libPath = new File(mFrameworkDir, frameworkFiles[i]);
                    String path = libPath.getPath();
                    // Skip the file if we alrady did it.
                    if (libFiles.contains(path)) {
                        continue;
                    }
                    // Skip the file if it is not a type we want to dexopt.
                    if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
                        continue;
                    }
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(path)) {
                            mInstaller.dexopt(path, Process.SYSTEM_UID, true);
                            didDexOpt = true;
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Jar not found: " + path);
                    } catch (IOException e) {
                        Slog.w(TAG, "Exception reading jar: " + path, e);
                    }
                }
            }

            if (didDexOpt) {
                // If we had to do a dexopt of one of the previous
                // things, then something on the system has changed.
                // Consider this significant, and wipe away all other
                // existing dexopt files to ensure we don't leave any
                // dangling around.
                String[] files = mDalvikCacheDir.list();
                if (files != null) {
                    for (int i=0; i<files.length; i++) {
                        String fn = files[i];
                        if (fn.startsWith("data@app@")
                                || fn.startsWith("data@app-private@")) {
                            Slog.i(TAG, "Pruning dalvik file: " + fn);
                            (new File(mDalvikCacheDir, fn)).delete();
                        }
                    }
                }
            }

            // Find base frameworks (resource packages without code).
            mFrameworkInstallObserver = new AppDirObserver(
                mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
            mFrameworkInstallObserver.startWatching();
            scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanMode | SCAN_NO_DEX, 0);
            
            // Collect all system packages.
            mSystemAppDir = new File(Environment.getRootDirectory(), "app");//获得的是/system/app目录
            mSystemInstallObserver = new AppDirObserver(
                mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
            mSystemInstallObserver.startWatching();
            scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
            
            // Collect all vendor packages.
            mVendorAppDir = new File("/vendor/app");//获得的是/vendor/app里面主要是设备厂家提供的应用程序。
            mVendorInstallObserver = new AppDirObserver(
                mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
            mVendorInstallObserver.startWatching();
            scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);//scanDieLI用来安装里面的应用程序。

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

            // Prune any system packages that no longer exist.
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();
                    if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
                            && !mPackages.containsKey(ps.name)
                            && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
                        psit.remove();
                        String msg = "System package " + ps.name
                                + " no longer exists; wiping its data";
                        reportSettingsProblem(Log.WARN, msg);
                        mInstaller.remove(ps.name, 0);
                        mUserManager.removePackageForAllUsers(ps.name);
                    }
                }
            }
            
            mAppInstallDir = new File(dataDir, "app");
            //look for any incomplete package installations
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            //clean up list
            for(int i = 0; i < deletePkgsList.size(); i++) {
                //clean up here
                cleanupInstallFailedPackage(deletePkgsList.get(i));
            }
            //delete tmp files
            deleteTempPackageFiles();

            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                mAppInstallObserver = new AppDirObserver(
                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
                mAppInstallObserver.startWatching();
                scanDirLI(mAppInstallDir, 0, scanMode, 0);
    
                mDrmAppInstallObserver = new AppDirObserver(
                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
                mDrmAppInstallObserver.startWatching();
                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanMode, 0);
            } else {
                mAppInstallObserver = null;
                mDrmAppInstallObserver = null;
            }

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");

            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear.  This is really a hack, and means that apps can in some
            // cases get permissions that the user didn't initially explicitly
            // allow...  it would be nice to have some better way to handle
            // this situation.
            final boolean regrantPermissions = mSettings.mInternalSdkPlatform
                    != mSdkVersion;
            if (regrantPermissions) Slog.i(TAG, "Platform changed from "
                    + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
                    + "; regranting permissions for internal storage");
            mSettings.mInternalSdkPlatform = mSdkVersion;
            
            updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);

            // can downgrade to reader
            mSettings.writeLPr();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            // Now after opening every single application zip, make sure they
            // are all flushed.  Not really needed, but keeps things nice and
            // tidy.
            Runtime.getRuntime().gc();

            mRequiredVerifierPackage = getRequiredVerifierLPr();
        } // synchronized (mPackages)
        } // synchronized (mInstallLock)

未完善,

© 著作权归作者所有

共有 人打赏支持
会飞的章鱼
粉丝 3
博文 17
码字总数 12563
作品 0
深圳
程序员
私信 提问
AndroidManifest.xml文件详解(manifest)

语法(SYNTAX): . . . 被包含于(CONTAINED IN): 无 必须包含的元素(MUST CONTAIN): 可能包含的元素(CAN CONTAIN): 说明(DESCRIPTION): 这个元素是AndroidManifest.xml文件的根...

长平狐
2012/10/16
512
0
Android:Apk插件出现Permission Denial: starting Intent错

Android跳转插件时出现Permission Denial错误主要错误是:在入口Activity中没有添加<action android:name="android.intent.action.MAIN" />。 <activity android:name="Activity"> <intent-f......

习惯_搬砖
2014/11/19
0
0
在 Android 3.0 平台上创建和解析 XML

简介: Android 是最常用的智能手机平台,它在移动平板电脑上也能发挥作用。XML 是数据交换的标准媒介。您可以对标准 XML 解析、标准 XML 转换和 Android 使用相同的生成器、解析器和转换器 ...

IBMdW
2011/11/14
665
0
Android 程序的主要组成部分 和 Manifest 文件

Android 程序的主要组成部分 和 Manifest 文件 Android由松耦合的组件组成,并使用Manifest 绑定在一起;Manifest描述了每个组件和他们之间的交互关系,还用于应用程序的元数据、其硬件和平台...

骑着乌龟的蜗牛
2014/12/09
0
0
[PHP]通过 PHP for Android 利用PHP编写Android应用教程

本文摘自 IT博客 http://www.zhangdafen.com 概述 Android 上的主要开发语言是Java,让很多PHPer觉得非常遗憾。但是自从ASE(Android Scripting Environment-Android脚本环境)诞生后,允许用...

81028386
2013/03/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

用Redis实现“秒杀”系统

导论 曾经被问过好多次怎样实现秒杀系统的问题。昨天又在CSDN架构师微信群被问到了。因此这里把我设想的实现秒杀系统的价格设计分享出来。供大家参考。 秒杀系统的架构设计 秒杀系统,是典型...

小刀爱编程
6分钟前
0
0
GO redis 相关操作

在gopath 目录下安装 go get github.com/garyburd/redigo/redis package mainimport ("fmt""github.com/garyburd/redigo/redis")//定义一个全局链接池变量var pool *redis.Pool//......

汤汤圆圆
43分钟前
9
0
java8性特性,常用的lambda表达式

1、抽取多个对象中的某个属性,用数组接收 List<Student> students = new ArrayList<>(); List<String> names =students.stream().map(Student::getName).collect(Collectors.toList()); 2、......

Boss-x
44分钟前
12
0
flutter 子组件与父组件

无论是子组件还是父组件,任何时候initState()只执行一次,如果需要判断 就在build里面进行,不然无效的。

大灰狼wow
46分钟前
4
0
Rancher Labs引入全球首个多集群、多租户的Prometheus支持!

近日,Rancher Labs宣布加强对Prometheus的支持,提高Kubernetes集群的可见度。Rancher也因此成为唯一一个在多集群、多租户环境中支持Prometheus的解决方案。 Prometheus正迅速成为监控云原生...

RancherLabs
48分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部