应用程序包的安装是android的特点

APK为AndroidPackage的缩写

Android应用安装有如下四种方式:

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

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

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

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

应用安装的流程及路径 
应用安装涉及到如下几个目录:

system/app ---------------系统自带的应用程序,获得adb root权限才能删除

data/app  ---------------用户程序安装的目录。安装时把                                                                                                      apk文件复制到此目录
data/data ---------------存放应用程序的数据
data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)

安装过程:

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

卸载过程:

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

安装应用的过程解析

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

(源文件路径:android\frameworks\base\services\java\com\android\server\PackageManagerService.java)

PackageManagerService服务启动的流程:

1.首先扫描安装“system\framework”目录下的jar包

 // 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);

2.扫描安装系统system/app的应用程序

  // 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);

3.制造商的目录下/vendor/app应用包

 // 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);

4.扫描“data\app”目录,即用户安装的第三方应用

scanDirLI(mAppInstallDir, 0, scanMode, 0);

5.扫描" data\app-private"目录,即安装DRM保护的APK文件(一个受保护的歌曲或受保 护的视频是使用 DRM 保护的文件)

scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,scanMode, 0);

扫描方法的代码清单

private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {String[] files = dir.list();if (files == null) {Log.d(TAG, "No files in app dir " + dir);return;}if (false) {Log.d(TAG, "Scanning app dir " + dir);}int i;for (i=0; i<files.length; i++) {File file = new File(dir, files[i]);if (!isPackageFilename(files[i])) {// Ignore entries which are not apk'scontinue;}PackageParser.Package pkg = scanPackageLI(file,flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);// Don't mess around with apps in system partition.if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {// Delete the apkSlog.w(TAG, "Cleaning up failed install of " + file);file.delete();}}}

并且从该扫描方法中可以看出调用了scanPackageLI()

private PackageParser.Package scanPackageLI(File scanFile,

int parseFlags, int scanMode, long currentTime)

跟踪scanPackageLI()方法后发现,程序经过很多次的if else 的筛选,最后判定可以安装后调用了 mInstaller.install

if (mInstaller != null) {int ret = mInstaller.install(pkgName, useEncryptedFSDir,  pkg.applicationInfo.uid,pkg.applicationInfo.uid);if(ret < 0) {// Error from installermLastScanError =    PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;return null;}}

mInstaller.install()  通过

LocalSocketAddress address = new LocalSocketAddress(

"installd", LocalSocketAddress.Namespace.RESERVED);

指挥installd在C语言的文件中完成工作

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

二、从网络上下载应用:

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

/* Called when a downloaded package installation has been confirmed by the user */

由英文注释可见PackageManagerService类的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 outSlog.e(TAG, "Cannot bind to media container service");for (HandlerParams params : mPendingInstalls) {mPendingInstalls.remove(0);// Indicate service bind errorparams.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()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法

 @Overridevoid 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;}

-----------------------------------------------------------------------------------------

  private 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 returnedres.returnCode = PackageManager.INSTALL_SUCCEEDED;// Retrieve PackageSettings and parse packageint 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 packageif ((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 sdcardSlog.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 renamesetApplicationInfoPaths(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());***********************省略若干**************************************************
}

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

三、从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)

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

四,从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, OnCancelListenerpublic 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 displayedmOkPanel = (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);}

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

转自:https://blog.csdn.net/hdhd588/article/details/6739281

禁止Android安装某些apk应用相关推荐

  1. Android安装更新 apk,适用于android6.0及以上安卓版本。

    Android应用中apk下载更新,适用于android 9及以下安卓版本. 直接上代码: 一.在主配置文件中写权限. <uses-permission android:name="a ...

  2. 教你如何反编译Android安装文件apk来偷窥源代码

    本文章首发于浩瀚先森博客,地址:http://www.guohao1206.com/2016/08/23/970.html 1. 准备 - java环境 安装java并配置环境 => JAVA环 ...

  3. android 安装器,APK安装器

    详情 APK安装器是一款最新推出的功能非常强大的安卓软件安装器.APK安装器颠覆了以往的安卓手机常规的安装方式和规则.操作非常简单,功能十分多样化,而且不会显示在你的手机桌面上占用你的手机桌面影响美观 ...

  4. android安装服务apk下载,快爆工具服务app下载

    好游快爆工具服务免费版是为原神玩家推出的地图资源查看器,数据可以同步到你的好游快爆的账号.只需要在app里打开悬浮窗的功能就可以悬浮在页面上,然后打开原神游戏就可以在屏幕上显示地图资源查看页面了.而且 ...

  5. android安装服务apk下载,华为服务中心下载

    华为服务中心下载是一款非常好用的华为手机服务软件.这里对用户来说,可以非常轻松的玩转华为手机,可以享受到各种华为手机的服务,就算你换了手机号也可以一键进行手机号的更换.感兴趣的话那就不要错过了,赶紧来 ...

  6. Android完全禁止第三方软件安装的方法

    这段时间在给公司的产品做CTA认证,公司的产品声明不允许第三方软件安装,所以需要禁止掉APK的安装功能.一开始我把Packageinstaller.apk从系统里面删了,试了一下,放一个APK到SD卡 ...

  7. Android代码实现APK文件的安装与卸载

    Android代码实现APK文件的安装与卸载 Android程序使用代码的安装和卸载!!! 安装: String str = "/CanavaCancel.apk"; String ...

  8. 探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法

    前言 相信这样一个问题,大家都不会陌生, "有什么的方法可以使Android的程序APK不用安装,而能够直接启动". 发现最后的结局都是不能实现这个美好的愿望,而腾讯Android ...

  9. Android插件化开发之用DexClassLoader加载未安装的APK资源文件来实现app切换背景皮肤

    第一步.先制做一个有我们需要的图片资源的APK 如下图,这里有个about_log.png,我们需要生成apk文件. 生成的apk文件如果你不到项目的文件夹里面去取apk,想通过命令放到手机里面去可以 ...

最新文章

  1. python表白源代码加音乐_python炫酷烟花表白源代码
  2. 如何把自己的经历写成小说_《诡秘小说》:读者与作者共同创作,难分真假,午夜不敢独自看!...
  3. Mysql身份认证漏洞及利用(CVE-2012-2122) 补充测试用例
  4. java基础之-I/O流和File类解析
  5. springmvc错误java.lang.IllegalArgumentException
  6. 虚拟化平台cloudstack(4)——几个异常
  7. 新技术将让硬盘密度再提五倍
  8. Unity3D基础12:碰撞体
  9. PowerShell 使用PowerTab加强Tab键自动补全
  10. win7安装python3.6失败_win7下python3.6安装配置方法图文教程
  11. 计算机网络复习(第六版)
  12. 时间分集、空间/天线分集、频率分集——无线通信中的分集技术
  13. 壳聚糖/纳米金水凝胶/纳米木质素/掺杂二硫化钼/微米级Ag2O2掺杂壳聚糖水凝胶的制备研究
  14. Windows 7可以拯救微软Netbook市场
  15. https://是什么?HTTPS和HTTP有什么不一样?如何申请SSL(HTTPS)证书?
  16. Java零散知识点XXXXXXXXX
  17. ecshop小京东的模板切换到smarty3.1.3之去掉原生的php语法
  18. 如何解释反向代理与正向代理
  19. pta 6-8 使用函数求Fibonacci数 (15 分)
  20. 269 t101 对称二叉树

热门文章

  1. js中数组的几种循环方式
  2. oppo A57(全网通)一键救砖,轻松刷回官方系统。
  3. NB-IoT 的“前世今生” 1
  4. Mbus新增主动报警功能,简单问题的波折路程。
  5. Vuex是如何工作的?
  6. linq和lambda_最小起订量:应用于模拟对象的Linq,Lambda和谓词
  7. 海上垂直无人机垂直起降平台
  8. android下运行时动态链接dlopen()和dlsym()的实现
  9. hosts文件详解--localhost和127.0.0.1
  10. linux中解压rar文件