Android应用程序安装过程解析


2017-03-02-17077393_314135475655975_7855162741030387712_n.jpg

1.程序安装的4大步骤

(1) 拷贝apk文件到指定目录

在Android系统中,apk安装文件是会被保存起来的,默认情况下,用户安装的apk首先会被拷贝到 /data/app 目录下。

/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件,而系统出厂的apk文件则被放到了 /system 分区下,包括 /system/app,/system/vendor/app,以及 /system/priv-app 等等,该分区只有Root权限的用户才能访问,这也就是为什么在没有Root手机之前,我们无法删除系统出厂的app的原因了。

(2) 解压apk,拷贝文件,创建应用的数据目录

为了加快app的启动速度,apk在安装的时候,会首先将app的可执行文件(dex)拷贝到 /data/dalvik-cache 目录,缓存起来。

然后,在/data/data/目录下创建应用程序的数据目录(以应用的包名命名),存放应用的相关数据,如数据库、xml文件、cache、二进制的so动态库等等。

(3) 解析apk的AndroidManifinest.xml文件

Android系统中,也有一个类似注册表的东西,用来记录当前所有安装的应用的基本信息,每次系统安装或者卸载了任何apk文件,都会更新这个文件。这个文件位于如下目录:

/data/system/packages.xml

系统在安装apk的过程中,会解析apk的AndroidManifinest.xml文件,提取出这个apk的重要信息写入到packages.xml文件中,这些信息包括:权限、应用包名、APK的安装位置、版本、userID等等。

由此,我们就知道了为啥一些应用市场和软件管理类的app能够很清楚地知道当前手机所安装的所有的app,以及这些app的详细信息了。

另外一件事就是Linux的用户Id和用户组Id,以便他可以获得合适的运行权限。

以上这些都是由PackageServiceManager完成的,下面我们会重点介绍PackageServiceManager。

(4) 显示快捷方式

这些应用程序只是相当于在PackageManagerService服务注册好了,如果我们想要在Android桌面上看到这些应用程序,还需要有一个Home应用程序,负责从PackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。在Android系统中,负责把系统中已经安装的应用程序在桌面中展现出来的Home应用程序就是Launcher了

2.PackageManagerService的启动过程

Android系统在启动的过程中,会启动一个应用程序管理服务PackageManagerService,这个服务负责扫描系统中特定的目录,找到里面的应用程序文件,即以Apk为后缀的文件,然后对这些文件进解析,得到应用程序的相关信息。应用程序管理服务PackageManagerService安装应用程序的过程,其实就是解析析应用程序配置文件AndroidManifest.xml的过程,并从里面得到得到应用程序的相关信息,例如得到应用程序的组件Activity、Service、Broadcast Receiver和Content Provider等信息,有了这些信息后,通过ActivityManagerService这个服务,我们就可以在系统中正常地使用这些应用程序了。应用程序管理服务PackageManagerService是系统启动的时候由SystemServer组件启动的,启后它就会执行应用程序安装的过程,因此,本文将从SystemServer启动PackageManagerService服务的过程开始分析系统中的应用程序安装的过程。

下面我们具体分析每一个步骤。

Step 1. SystemServer.main

这个函数定义在frameworks/base/services/Java/com/android/server/SystemServer.java文件中:

public class SystemServer  {      ......        native public static void init1(String[] args);        ......        public static void main(String[] args) {          ......            init1(args);            ......      }        ......  }  

SystemServer组件是由Zygote进程负责启动的,启动的时候就会调用它的main函数,这个函数主要调用了JNI方法init1来做一些系统初始化的工作。

Step 2. SystemServer.init1

这个函数是一个JNI方法,实现在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中:

namespace android {    extern "C" int system_init();    static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)  {      system_init();  }    /*  * JNI registration.  */  static JNINativeMethod gMethods[] = {      /* name, signature, funcPtr */      { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },  };    int register_android_server_SystemServer(JNIEnv* env)  {      return jniRegisterNativeMethods(env, "com/android/server/SystemServer",              gMethods, NELEM(gMethods));  }    }; // namespace android  

这个函数很简单,只是调用了system_init函数来进一步执行操作。

Step 3. libsystem_server.system_init

函数system_init实现在libsystem_server库中,源代码位于frameworks/base/cmds/system_server/library/system_init.cpp文件中:

extern "C" status_t system_init()  {      LOGI("Entered system_init()");        sp proc(ProcessState::self());        sp sm = defaultServiceManager();      LOGI("ServiceManager: %p\n", sm.get());        sp grim = new GrimReaper();      sm->asBinder()->linkToDeath(grim, grim.get(), 0);        char propBuf[PROPERTY_VALUE_MAX];      property_get("system_init.startsurfaceflinger", propBuf, "1");      if (strcmp(propBuf, "1") == 0) {          // Start the SurfaceFlinger          SurfaceFlinger::instantiate();      }        // Start the sensor service      SensorService::instantiate();        // On the simulator, audioflinger et al don't get started the      // same way as on the device, and we need to start them here      if (!proc->supportsProcesses()) {            // Start the AudioFlinger          AudioFlinger::instantiate();            // Start the media playback service          MediaPlayerService::instantiate();            // Start the camera service          CameraService::instantiate();            // Start the audio policy service          AudioPolicyService::instantiate();      }        // And now start the Android runtime.  We have to do this bit      // of nastiness because the Android runtime initialization requires      // some of the core system services to already be started.      // All other servers should just start the Android runtime at      // the beginning of their processes's main(), before calling      // the init function.      LOGI("System server: starting Android runtime.\n");        AndroidRuntime* runtime = AndroidRuntime::getRuntime();        LOGI("System server: starting Android services.\n");      runtime->callStatic("com/android/server/SystemServer", "init2");        // If running in our own process, just go into the thread      // pool.  Otherwise, call the initialization finished      // func to let this process continue its initilization.      if (proc->supportsProcesses()) {          LOGI("System server: entering thread pool.\n");          ProcessState::self()->startThreadPool();          IPCThreadState::self()->joinThreadPool();          LOGI("System server: exiting thread pool.\n");      }        return NO_ERROR;  }  

这个函数首先会初始化SurfaceFlinger、SensorService、AudioFlinger、MediaPlayerService、CameraService和AudioPolicyService这几个服务,然后就通过系统全局唯一的AndroidRuntime实例变量runtime的callStatic来调用SystemServer的init2函数了。关于这个AndroidRuntime实例变量runtime的相关资料,可能参考前面一篇文章Android应用程序进程启动过程的源代码分析一文。

Step 4. AndroidRuntime.callStatic

这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

/* * Call a static Java Programming Language function that takes no arguments and returns void. */  status_t AndroidRuntime::callStatic(const char* className, const char* methodName)  {      JNIEnv* env;      jclass clazz;      jmethodID methodId;        env = getJNIEnv();      if (env == NULL)          return UNKNOWN_ERROR;        clazz = findClass(env, className);      if (clazz == NULL) {          LOGE("ERROR: could not find class '%s'\n", className);          return UNKNOWN_ERROR;      }      methodId = env->GetStaticMethodID(clazz, methodName, "()V");      if (methodId == NULL) {          LOGE("ERROR: could not find method %s.%s\n", className, methodName);          return UNKNOWN_ERROR;      }        env->CallStaticVoidMethod(clazz, methodId);        return NO_ERROR;  }

这个函数调用由参数className指定的java类的静态成员函数,这个静态成员函数是由参数methodName指定的。上面传进来的参数className的值为"com/android/server/SystemServer",而参数methodName的值为"init2",因此,接下来就会调用SystemServer类的init2函数了。

Step 5. SystemServer.init2

这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

public class SystemServer  {      ......        public static final void init2() {          Slog.i(TAG, "Entered the Android system server!");          Thread thr = new ServerThread();          thr.setName("android.server.ServerThread");          thr.start();      }  }  

这个函数创建了一个ServerThread线程,PackageManagerService服务就是这个线程中启动的了。这里调用了ServerThread实例thr的start函数之后,下面就会执行这个实例的run函数了。

Step 6. ServerThread.run

这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

class ServerThread extends Thread {      ......        @Override      public void run() {          ......            IPackageManager pm = null;            ......            // Critical services...          try {              ......                Slog.i(TAG, "Package Manager");              pm = PackageManagerService.main(context,                          factoryTest != SystemServer.FACTORY_TEST_OFF);                ......          } catch (RuntimeException e) {              Slog.e("System", "Failure starting core service", e);          }            ......      }        ......  }  

这个函数除了启动PackageManagerService服务之外,还启动了其它很多的服务,例如在前面学习Activity和Service的几篇文章中经常看到的ActivityManagerService服务,有兴趣的读者可以自己研究一下。

Step 7. PackageManagerService.main

这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

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

3.常见的4种安装场景

1.系统应用安装――开机时完成,没有安装界面

2.网络下载应用安装――通过market应用完成,没有安装界面

3.ADB工具安装――没有安装界面。

4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由 packageinstaller.apk应用处理安装及卸载过程的界面。

安装过程:

复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。

卸载过程:

删除安装过程中在上述三个目录下创建的文件及目录。

(1)系统应用安装――开机时完成,没有安装界面

PackageManagerService处理各种应用的安装,卸载,管理等工作,开机时由systemServer启动此服务

在创建这个PackageManagerService服务实例时,会在PackageManagerService类的构造函数中开始执行安装应用程序的过程:

PackageManagerService核心代码

 class PackageManagerService extends IPackageManager.Stub {      ......        public PackageManagerService(Context context, boolean factoryTest) {          ......      mSetting = new Setting();        synchronized (mInstallLock) {              synchronized (mPackages) {                  ......                    File dataDir = Environment.getDataDirectory();                  mAppDataDir = new File(dataDir, "data");                  mSecureAppDataDir = new File(dataDir, "secure/data");          mRestoredSetting = mASetting.readLP();                mDrmAppPrivateInstallDir = new File(dataDir, "app-private");                    ......                    mFrameworkDir = new File(Environment.getRootDirectory(), "framework");                  mDalvikCacheDir = new File(dataDir, "dalvik-cache");                    ......                    // 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");                  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");                  mVendorInstallObserver = new AppDirObserver(                      mVendorAppDir.getPath(), OBSERVER_EVENTS, true);                  mVendorInstallObserver.startWatching();                  scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM                      | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);                      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);                    ......          final boolean regrantPermissions = mSetting.mInternalSDKplatform != mSdkVersion;        updatePermissionsLP(null,null,true,r�regrantPermissions .regrantPermissions );        msetting.writeLP();            }          }      }        ......  }  

这里会调用scanDirLI函数来扫描移动设备上的下面这五个目录中的Apk文件

    /system/framework    /system/app    /vendor/app    /data/app    /data/app-private

由于Android每次启动的时候都需要安装一次信息,但是有些信息是保持不变的,例如Linux用户组Id,PackageManagerService 每次安装程序之后,都会把这些程序的信息保存下来,以便下次使用,
恢复上一次程序的安装信息是通过PackageManagerService 的成员变量mSetting的readLP()来实现的,恢复信息之后就开始扫描和安装app了。

扫描安装app

PackageManagerService.scanDirLI

这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

 class PackageManagerService extends IPackageManager.Stub {      ......        private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {          String[] files = dir.list();          ......            int i;          for (i=0; i

对于目录中的每一个文件,如果是以后Apk作为后缀名,那么就调用scanPackageLI函数来对它进行解析和安装。

PackageManagerService.scanPackageLI

这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

class PackageManagerService extends IPackageManager.Stub {      ......        private PackageParser.Package scanPackageLI(File scanFile,              int parseFlags, int scanMode, long currentTime) {          ......            String scanPath = scanFile.getPath();          parseFlags |= mDefParseFlags;          PackageParser pp = new PackageParser(scanPath);                    ......            final PackageParser.Package pkg = pp.parsePackage(scanFile,              scanPath, mMetrics, parseFlags);            ......            return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime);      }        ......  }  

这个函数首先会为这个Apk文件创建一个PackageParser实例,接着调用这个实例的parsePackage函数来对这个Apk文件进行解析。这个函数最后还会调用另外一个版本的scanPackageLI函数把来解析后得到的应用程序信息保存在PackageManagerService中。

PackageParser.parsePackage

这个函数定义在frameworks/base/core/java/android/content/pm/PackageParser.java文件中:

public class PackageParser {      ......        public Package parsePackage(File sourceFile, String destCodePath,              DisplayMetrics metrics, int flags) {          ......            mArchiveSourcePath = sourceFile.getPath();            ......            XmlResourceParser parser = null;          AssetManager assmgr = null;          boolean assetError = true;          try {              assmgr = new AssetManager();              int cookie = assmgr.addAssetPath(mArchiveSourcePath);              if(cookie != 0) {                  parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");                  assetError = false;              } else {                  ......              }          } catch (Exception e) {              ......          }            ......            String[] errorText = new String[1];          Package pkg = null;          Exception errorException = null;          try {              // XXXX todo: need to figure out correct configuration.              Resources res = new Resources(assmgr, metrics, null);              pkg = parsePackage(res, parser, flags, errorText);          } catch (Exception e) {              ......          }            ......            parser.close();          assmgr.close();            // Set code and resource paths          pkg.mPath = destCodePath;          pkg.mScanPath = mArchiveSourcePath;          //pkg.applicationInfo.sourceDir = destCodePath;          //pkg.applicationInfo.publicSourceDir = destRes;          pkg.mSignatures = null;            return pkg;      }        ......  }  

每一个Apk文件都是一个归档文件,它里面包含了Android应用程序的配置文件AndroidManifest.xml,这里主要就是要对这个配置文件就行解析了,从Apk归档文件中得到这个配置文件后,就调用另一外版本的parsePackage函数对这个应用程序进行解析了:

public class PackageParser {      ......        private Package parsePackage(              Resources res, XmlResourceParser parser, int flags, String[] outError)              throws XmlPullParserException, IOException {          ......            String pkgName = parsePackageName(parser, attrs, flags, outError);                    ......            final Package pkg = new Package(pkgName);            ......            int type;            ......                    TypedArray sa = res.obtainAttributes(attrs,              com.android.internal.R.styleable.AndroidManifest);            ......            while ((type=parser.next()) != parser.END_DOCUMENT              && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {                  if (type == parser.END_TAG || type == parser.TEXT) {                      continue;                  }                    String tagName = parser.getName();                  if (tagName.equals("application")) {                      ......                        if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {                          return null;                      }                  } else if (tagName.equals("permission-group")) {                      ......                  } else if (tagName.equals("permission")) {                      ......                  } else if (tagName.equals("permission-tree")) {                      ......                  } else if (tagName.equals("uses-permission")) {                      ......                  } else if (tagName.equals("uses-configuration")) {                      ......                  } else if (tagName.equals("uses-feature")) {                      ......                  } else if (tagName.equals("uses-sdk")) {                      ......                  } else if (tagName.equals("supports-screens")) {                      ......                  } else if (tagName.equals("protected-broadcast")) {                      ......                  } else if (tagName.equals("instrumentation")) {                      ......                  } else if (tagName.equals("original-package")) {                      ......                  } else if (tagName.equals("adopt-permissions")) {                      ......                  } else if (tagName.equals("uses-gl-texture")) {                      ......                  } else if (tagName.equals("compatible-screens")) {                      ......                  } else if (tagName.equals("eat-comment")) {                      ......                  } else if (RIGID_PARSER) {                      ......                  } else {                      ......                  }          }            ......            return pkg;      }        ......  }  

这里就是对AndroidManifest.xml文件中的各个标签进行解析了,各个标签的含义可以参考官方文档http://developer.android.com/guide/topics/manifest/manifest-intro.html,这里我们只简单看一下application标签的解析,这是通过调用parseApplication函数来进行的。

PackageParser.parseApplication

这个函数定义在frameworks/base/core/java/android/content/pm/PackageParser.java文件中:

public class PackageParser {      ......        private boolean parseApplication(Package owner, Resources res,              XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)              throws XmlPullParserException, IOException {          final ApplicationInfo ai = owner.applicationInfo;          final String pkgName = owner.applicationInfo.packageName;            TypedArray sa = res.obtainAttributes(attrs,              com.android.internal.R.styleable.AndroidManifestApplication);            ......            int type;          while ((type=parser.next()) != parser.END_DOCUMENT              && (type != parser.END_TAG || parser.getDepth() > innerDepth)) {                  if (type == parser.END_TAG || type == parser.TEXT) {                      continue;                  }                            String tagName = parser.getName();                  if (tagName.equals("activity")) {                      Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);                      ......                        owner.activities.add(a);                    } else if (tagName.equals("receiver")) {                      Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);                      ......                        owner.receivers.add(a);                  } else if (tagName.equals("service")) {                      Service s = parseService(owner, res, parser, attrs, flags, outError);                      ......                        owner.services.add(s);                  } else if (tagName.equals("provider")) {                      Provider p = parseProvider(owner, res, parser, attrs, flags, outError);                      ......                        owner.providers.add(p);                  } else if (tagName.equals("activity-alias")) {                      Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);                      ......                        owner.activities.add(a);                  } else if (parser.getName().equals("meta-data")) {                      ......                  } else if (tagName.equals("uses-library")) {                      ......                  } else if (tagName.equals("uses-package")) {                      ......                  } else {                      ......                  }          }            return true;      }        ......  }  

这里就是对AndroidManifest.xml文件中的application标签进行解析了,我们常用到的标签就有activity、service、receiver和provider,各个标签的含义可以参考官方文档http://developer.android.com/guide/topics/manifest/manifest-intro.html。这里解析完成后,一层层返回到Step 9中,调用另一个版本的scanPackageLI函数把来解析后得到的应用程序信息保存下来。

PackageManagerService.scanPackageLI

这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:

class PackageManagerService extends IPackageManager.Stub {      ......        // Keys are String (package name), values are Package.  This also serves      // as the lock for the global state.  Methods that must be called with      // this lock held have the prefix "LP".      final HashMap mPackages =          new HashMap();        ......        // All available activities, for your resolving pleasure.      final ActivityIntentResolver mActivities =      new ActivityIntentResolver();        // All available receivers, for your resolving pleasure.      final ActivityIntentResolver mReceivers =          new ActivityIntentResolver();        // All available services, for your resolving pleasure.      final ServiceIntentResolver mServices = new ServiceIntentResolver();        // Keys are String (provider class name), values are Provider.      final HashMap mProvidersByComponent =          new HashMap();        ......        private PackageParser.Package scanPackageLI(PackageParser.Package pkg,              int parseFlags, int scanMode, long currentTime) {          ......            synchronized (mPackages) {              ......                // Add the new setting to mPackages              mPackages.put(pkg.applicationInfo.packageName, pkg);                ......                int N = pkg.providers.size();              int i;              for (i=0; i

这个函数主要就是把前面解析应用程序得到的package、provider、service、receiver和activity等信息保存在PackageManagerService服务中了。

PackageManagerService的作用总结:

1)从apk, xml中载入pacakge信息, 存储到内部成员变量中, 用于后面的查找. 关键的方法是scanPackageLI().
2)各种查询操作, 包括query Intent操作.
3)install package和delete package的操作. 还有后面的关键方法是installPackageLI().

后面重点介绍installPackageLI,后面的额方式本质都会调用它。

(2)从网络上下载应用:

下载完成后,会自动调用Packagemanager的安装方法installPackage()

public void installPackage(             final Uri packageURI, final IPackageInstallObserver observer, final int flags,             final String installerPackageName) {         mContext.enforceCallingOrSelfPermission(                 android.Manifest.permission.INSTALL_PACKAGES, null);         Message msg = mHandler.obtainMessage(INIT_COPY);         msg.obj = new InstallParams(packageURI, observer, flags,                 installerPackageName);         mHandler.sendMessage(msg);     }  

通过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()方法

class PackageHandler extends Handler{                     *****************省略若干********************           public void handleMessage(Message msg) {              try {                  doHandleMessage(msg);              } finally {                  Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);              }          }     ******************省略若干**********************   }  

把信息发给doHandleMessage()方法,方法中用switch()语句进行判定传来Message

 void doHandleMessage(Message msg) {              switch (msg.what) {                               case INIT_COPY: {                      if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");                      HandlerParams params = (HandlerParams) msg.obj;                      int idx = mPendingInstalls.size();                      if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);                      // If a bind was already initiated we dont really                      // need to do anything. The pending install                      // will be processed later on.                      if (!mBound) {                          // If this is the only one pending we might                          // have to bind to the service again.                          if (!connectToService()) {                              Slog.e(TAG, "Failed to bind to media container service");                              params.serviceError();                              return;                          } else {                              // Once we bind to the service, the first                              // pending request will be processed.                              mPendingInstalls.add(idx, params);                          }                      } else {                          mPendingInstalls.add(idx, params);                          // Already bound to the service. Just make                          // sure we trigger off processing the first request.                          if (idx == 0) {                              mHandler.sendEmptyMessage(MCS_BOUND);                          }                      }                      break;                  }                  case MCS_BOUND: {                      if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");                      if (msg.obj != null) {                          mContainerService = (IMediaContainerService) msg.obj;                      }                      if (mContainerService == null) {                          // Something seriously wrong. Bail out                          Slog.e(TAG, "Cannot bind to media container service");                          for (HandlerParams params : mPendingInstalls) {                              mPendingInstalls.remove(0);                              // Indicate service bind error                              params.serviceError();                          }                          mPendingInstalls.clear();                      } else if (mPendingInstalls.size() > 0) {                          HandlerParams params = mPendingInstalls.get(0);                          if (params != null) {                              params.startCopy();                          }                      } else {                          // Should never happen ideally.                          Slog.w(TAG, "Empty queue");                      }                      break;                  }              ****************省略若干**********************  }  }  

public final boolean sendMessage (Message msg)

public final boolean sendEmptyMessage (int what)

两者参数有别。

然后调用抽象类HandlerParams中的一个startCopy()方法

abstract class HandlerParams {

final void startCopy() {

***************若干if语句判定否这打回handler消息*******

handleReturnCode();

}
}

handleReturnCode()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法

@Override         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);             }         }  

这时可以清楚的看见 processPendingInstall()被调用。

其中run()方法如下

run(){  synchronized (mInstallLock) {                          ************省略*****************                          installPackageLI(args, true, res);                        }  }  

instaPacakgeLI()args,res参数分析


//InstallArgs 是在PackageService定义的static abstract class InstallArgs 静态抽象类。

static abstract class InstallArgs {  *********************************************************************  其中定义了flag标志,packageURL,创建文件,拷贝apk,修改包名称,                      还有一些删除文件的清理,释放存储函数。      *********************************************************************  }    class PackageInstalledInfo {          String name;          int uid;          PackageParser.Package pkg;          int returnCode;          PackageRemovedInfo removedInfo;   }  -----------------------------------------------------------------------------------------  [java] view plain copyprivate void installPackageLI(InstallArgs args,            boolean newInstall, PackageInstalledInfo res) {        int pFlags = args.flags;        String installerPackageName = args.installerPackageName;        File tmpPackageFile = new File(args.getCodePath());        boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);        boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);        boolean replace = false;        int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE                | (newInstall ? SCAN_NEW_INSTALL : 0);        // Result object to be returned        res.returnCode = PackageManager.INSTALL_SUCCEEDED;        // Retrieve PackageSettings and parse package        int parseFlags = PackageParser.PARSE_CHATTY |        (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |        (onSd ? PackageParser.PARSE_ON_SDCARD : 0);        parseFlags |= mDefParseFlags;        PackageParser pp = new PackageParser(tmpPackageFile.getPath());        pp.setSeparateProcesses(mSeparateProcesses);        final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,                null, mMetrics, parseFlags);        if (pkg == null) {            res.returnCode = pp.getParseError();            return;        }        String pkgName = res.name = pkg.packageName;        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {            if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {                res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;                return;            }        }        if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {            res.returnCode = pp.getParseError();            return;        }        // Get rid of all references to package scan path via parser.        pp = null;        String oldCodePath = null;        boolean systemApp = false;        synchronized (mPackages) {            // Check if installing already existing package            if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {                String oldName = mSettings.mRenamedPackages.get(pkgName);                if (pkg.mOriginalPackages != null                        && pkg.mOriginalPackages.contains(oldName)                        && mPackages.containsKey(oldName)) {                    // This package is derived from an original package,                    // and this device has been updating from that original                    // name.  We must continue using the original name, so                    // rename the new package here.                    pkg.setPackageName(oldName);                    pkgName = pkg.packageName;                    replace = true;                } else if (mPackages.containsKey(pkgName)) {                    // This package, under its official name, already exists                    // on the device; we should replace it.                    replace = true;                }            }            PackageSetting ps = mSettings.mPackages.get(pkgName);            if (ps != null) {                oldCodePath = mSettings.mPackages.get(pkgName).codePathString;                if (ps.pkg != null && ps.pkg.applicationInfo != null) {                    systemApp = (ps.pkg.applicationInfo.flags &                            ApplicationInfo.FLAG_SYSTEM) != 0;                }            }        }        if (systemApp && onSd) {            // Disable updates to system apps on sdcard            Slog.w(TAG, "Cannot install updates to system apps on sdcard");            res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;            return;        }        if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {            res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;            return;        }        // Set application objects path explicitly after the rename        setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());        pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();        if (replace) {            replacePackageLI(pkg, parseFlags, scanMode,                    installerPackageName, res);        } else {            installNewPackageLI(pkg, parseFlags, scanMode,                    installerPackageName,res);        }    }   

最后判断如果以前不存在那么调用installNewPackageLI()

private void installNewPackageLI(PackageParser.Package pkg,              int parseFlags,int scanMode,              String installerPackageName, PackageInstalledInfo res) {       ***********************省略若干*************************************************          PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,                 System.currentTimeMillis());       ***********************省略若干**************************************************    }  

最后终于回到了和开机安装一样的地方.与开机方式安装调用统一方法。

(3)从ADB工具安装

其入口函数源文件为pm.java

(源文件路径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java)

其中\system\framework\pm.jar 包管理库

包管理脚本 \system\bin\pm 解析

showUsage就是使用方法

private static void showUsage() {           System.err.println("usage: pm [list|path|install|uninstall]");           System.err.println("       pm list packages [-f]");           System.err.println("       pm list permission-groups");           System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");           System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");           System.err.println("       pm list features");           System.err.println("       pm path PACKAGE");           System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");           System.err.println("       pm uninstall [-k] PACKAGE");           System.err.println("       pm enable PACKAGE_OR_COMPONENT");           System.err.println("       pm disable PACKAGE_OR_COMPONENT");           System.err.println("       pm setInstallLocation [0/auto] [1/internal] [2/external]");        **********************省略**************************     }  

安装时候会调用 runInstall()方法

private void runInstall() {        int installFlags = 0;        String installerPackageName = null;        String opt;        while ((opt=nextOption()) != null) {            if (opt.equals("-l")) {                installFlags |= PackageManager.INSTALL_FORWARD_LOCK;            } else if (opt.equals("-r")) {                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;            } else if (opt.equals("-i")) {                installerPackageName = nextOptionData();                if (installerPackageName == null) {                    System.err.println("Error: no value specified for -i");                    showUsage();                    return;                }            } else if (opt.equals("-t")) {                installFlags |= PackageManager.INSTALL_ALLOW_TEST;            } else if (opt.equals("-s")) {                // Override if -s option is specified.                installFlags |= PackageManager.INSTALL_EXTERNAL;            } else if (opt.equals("-f")) {                // Override if -s option is specified.                installFlags |= PackageManager.INSTALL_INTERNAL;            } else {                System.err.println("Error: Unknown option: " + opt);                showUsage();                return;            }        }        String apkFilePath = nextArg();        System.err.println("\tpkg: " + apkFilePath);        if (apkFilePath == null) {            System.err.println("Error: no package specified");            showUsage();            return;        }        PackageInstallObserver obs = new PackageInstallObserver();        try {            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,                    installerPackageName);            synchronized (obs) {                while (!obs.finished) {                    try {                        obs.wait();                    } catch (InterruptedException e) {                    }                }                if (obs.result == PackageManager.INSTALL_SUCCEEDED) {                    System.out.println("Success");                } else {                    System.err.println("Failure ["                            + installFailureToString(obs.result)                            + "]");                }            }        } catch (RemoteException e) {            System.err.println(e.toString());            System.err.println(PM_NOT_RUNNING_ERR);        }    }  

其中的

PackageInstallObserver obs = new PackageInstallObserver();                    mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,                    installerPackageName);

如果安装成功

obs.result == PackageManager.INSTALL_SUCCEEDED)

又因为有

IPackageManage mPm;

    mPm = IpackageManager.Stub.asInterface(ServiceManager.getService("package"));

Stub是接口IPackageManage的静态抽象类,asInterface是返回IPackageManager代理的静态方法。

因为class PackageManagerService extends IPackageManager.Stub

所以mPm.installPackage 调用

/* Called when a downloaded package installation has been confirmed by the user */public void installPackage(        final Uri packageURI, final IPackageInstallObserver observer, final int flags,final String installerPackageName) 

这样就是从网络下载安装的入口了。

(4)从SD卡安装

系统调用PackageInstallerActivity.java(/home/zhongda/androidSRC/vortex-8inch-for-hoperun/packages/apps/PackageInstaller/src/com/android/packageinstaller)

进入这个Activity会判断信息是否有错,然后调用

  private void initiateInstall()判断是否曾经有过同名包的安装,或者包已经安装

通过后执行private void startInstallConfirm() 点击OK按钮后经过一系列的安装信息的判断Intent跳转到

public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener     public void onCreate(Bundle icicle) {          super.onCreate(icicle);          Intent intent = getIntent();          mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);          mPackageURI = intent.getData();          initView();      }  

方法中调用了initView()方法

public void initView() {         requestWindowFeature(Window.FEATURE_NO_TITLE);         setContentView(R.layout.op_progress);         int installFlags = 0;         PackageManager pm = getPackageManager();         try {             PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,                      PackageManager.GET_UNINSTALLED_PACKAGES);             if(pi != null) {                 installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;             }         } catch (NameNotFoundException e) {         }         if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {             Log.w(TAG, "Replacing package:" + mAppInfo.packageName);         }         PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,                 mPackageURI);         mLabel = as.label;         PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);         mStatusTextView = (TextView)findViewById(R.id.center_text);         mStatusTextView.setText(R.string.installing);         mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);         mProgressBar.setIndeterminate(true);         // Hide button till progress is being displayed         mOkPanel = (View)findViewById(R.id.buttons_panel);         mDoneButton = (Button)findViewById(R.id.done_button);         mLaunchButton = (Button)findViewById(R.id.launch_button);         mOkPanel.setVisibility(View.INVISIBLE);         String installerPackageName = getIntent().getStringExtra(                 Intent.EXTRA_INSTALLER_PACKAGE_NAME);         PackageInstallObserver observer = new PackageInstallObserver();         pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);     }  

方法最后我们可以看到再次调用安装接口完成安装。

对于mSetting的介绍还不完善,后续会继续补充

本文是读过下面的几篇博客和Android系统源代码情景分析之后写成的,感谢各位作者。

参考:

http://ticktick.blog.51cto.com/823160/1669525
http://blog.csdn.net/hdhd588/article/details/6739281
http://blog.csdn.net/luoshengyang/article/details/6766010
《Android系统源代码情景分析》

更多相关文章

  1. Android(安卓)NDK 下的宽字符编码转换及icu库的使用
  2. NDK进阶实例
  3. Android打开系统文件管理器
  4. Android(安卓)SharedPreferences 的 getsharedpreference(name,m
  5. Android(安卓)studio如何生成aar包
  6. 一步一坑学android之禁用Appt2(andriod studio3.0)
  7. Android镜像文件ramdisk.img,system.img,userdata.img介绍
  8. Ubuntu 16.04 LTS 编译 Android(安卓)7.1
  9. Android应用程序的打包,安装,启动

随机推荐

  1. Android(安卓)中的内容观察者ContentObse
  2. android 4.0.1源码编译,学习错误解决
  3. Android(安卓)CRC16计算产生校验码
  4. Android(安卓)SDK国内镜像
  5. Android(安卓)Studio 视图预览不显示了,
  6. android不同activity共享数据的几种方法
  7. Activity的属性之—launchMode
  8. Android(安卓)Studio 在默认build.gradle
  9. 如何用Android(安卓)studio构建项目
  10. SQLite数据库浅谈