android系统apk安装过程和原理

2021-10-10 15:30:24 2点赞 0收藏 0评论

APK为AndroidPackage的缩写

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

android系统apk安装过程和原理

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启动此服务

(源文件路径:androidframeworksbaseservicesjavacomandroidserverPackageManagerService.java)

PackageManagerService服务启动的流程:

1.首先扫描安装“systemframework”目录下的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.扫描“dataapp”目录,即用户安装的第三方应用

scanDirLI(mAppInstallDir, 0, scanMode, 0);

5.扫描" dataapp-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's

continue;

}

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 apk

Slog.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 installer

mLastScanError = 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 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;

}

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

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

***********************省略若干**************************************************

}

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

三、从ADB工具安装

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

(源文件路径:androidframeworksbasecmdspmsrccomandroidcommandspmpm.java)

其中systemframeworkpm.jar 包管理库

包管理脚本 systembinpm 解析

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

}

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

展开 收起

ihuman 洪恩 识字子集拼音思维ABC会员永久包3-6岁儿童早教启蒙礼物玩具 识字会员终身包

ihuman 洪恩 识字子集拼音思维ABC会员永久包3-6岁儿童早教启蒙礼物玩具 识字会员终身包

268元起

Microsoft 微软 OFFICE 365 家庭版 会员

Microsoft 微软 OFFICE 365 家庭版 会员

249元起

任天堂 Nintendo Switch《舞力全开 Just Dance》 游戏兑换卡

任天堂 Nintendo Switch《舞力全开 Just Dance》 游戏兑换卡

279元起

WPS 金山软件 WPS 超级会员 3年卡

WPS 金山软件 WPS 超级会员 3年卡

308元起

Microsoft 微软 Office 365 个人版

Microsoft 微软 Office 365 个人版

177元起

Microsoft 微软 OFFICE 365 个人版 办公软件

Microsoft 微软 OFFICE 365 个人版 办公软件

185元起

Microsoft 微软 到手18.2元/月 微软office365家庭版microsoft365增强版15个月

Microsoft 微软 到手18.2元/月 微软office365家庭版microsoft365增强版15个月

275元起

WPS超级会员Pro套餐4年卡1488天官方正版pdf转word排版

WPS超级会员Pro套餐4年卡1488天官方正版pdf转word排版

676.4元起

Microsoft 微软 office专业版永久激活码office2019增强版终身版outlook密钥

Microsoft 微软 office专业版永久激活码office2019增强版终身版outlook密钥

249元起

WPS超级会员4年套餐pdf转word排版PPT润色模板素材店铺

WPS超级会员4年套餐pdf转word排版PPT润色模板素材店铺

暂无报价

国行版 Switch体感游戏套装 《健身环大冒险》

国行版 Switch体感游戏套装 《健身环大冒险》

439元起

WPS 金山软件 会员季卡

WPS 金山软件 会员季卡

59.85元起

Microsoft 微软 价保到618 微软office365办公软件microsoft365

Microsoft 微软 价保到618 微软office365办公软件microsoft365

235元起

Microsoft 微软 活动6天 office365家庭版microsoft365订阅密钥

Microsoft 微软 活动6天 office365家庭版microsoft365订阅密钥

235元起

WPS超级会员2年pdf转word官方正版思维导图排版简历模板赠AI会员

WPS超级会员2年pdf转word官方正版思维导图排版简历模板赠AI会员

218.5元起

自助挂号应用服务

自助挂号应用服务

15000元起
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

相关好价推荐
查看更多好价

相关文章推荐

更多精彩文章
更多精彩文章
最新文章 热门文章
0
扫一下,分享更方便,购买更轻松