Android——APK 安装过程 及 原理 详解

安卓 APK 安装过程详解 在安卓设备上安装应用程序的过程中,APK(Android Package)文件是最常见的安装文件格式。为了顺利地在设备上安装APK,我们需要确保设备与计算机之间的ADB(Android Debug Bridge)连接正常,并且有适当的权限来执行各种文件操作。本篇文章将详细介绍从连接设备到成功安装APK的整个过程。通过以上步骤,您可以成功地在安卓设备上安装APK文件。这些操作不仅让您了解了ADB工具的基本使用方法,还教会您如何修改设备的文件权限以便进行各种安装操作。 阅读详情

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'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 的筛选,最后判定 可以安装apk后,调用了 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 

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

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

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

Pm.java 文件里的 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

源码路径:android/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

进入这个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); }



方法最后 我们可以看到 再次调用安装接口 完成安装,相当于 又 调用了 网络安装。


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

总结:

1.系统应用安装――开机时完成

2.网络下载应用安装――最后 会 调用  系统应用安装 的 scanPackageLI 接口;

3.ADB工具安装――最后 会 调用   网络下载应用安装 的installPackage 接口,从而 相当于 走的 还是系统应用安装 的 路径;

4.第三方应用安装――由 packageinstaller.apk 应用处理安装及卸载,最后也会 调用  网络下载应用安装 的installPackage 接口,从而 相当于 走的 还是系统应用安装 的 路径。

APK签名机制原理详解 众所周知,Android系统在安装Apk的过程中,会对Apk进行签名校验,校验通过后才能安装成功。那你知道签名校验的机制是什么?具体校验的是什么内容吗?申请第三方SDK(如微信支付)时填入的SAH1值是什么?目前众多的快速批量打包方案又是如何绕过签名检验的?我将通过一系列的文章来解开这些疑惑。 阅读详情

相关推荐

libfranka---joint_impendence_control例程分析

joint_impedance_control.cpp例程分析 部分内容来自链接,我个人以初学者的角度对代码进行了更加细致的解释。 核心部分: // Set and initialize trajectory parameters. const double radius = 0.05; const double vel_max = 0.25; const double acceleration_time = 2.0; const double run_time = 20.0; d

weixin_41567783的博客 1121

APK 安装过程 及 原理 详解

APK为AndroidPackage的缩写 Android应用安装有如下四种方式: 1.系统应用安装――开机时完成,没有安装界面 2.网络下载应用安装――通过market应用完成,没有安装界面 3.ADB工具安装――没有安装界面。 4.第三方应用安装――通过SD卡里的APK文件安装,...

772

从零到一:RK3588平台上的星闪模块驱动移植全解析

本文详细解析了在RK3588平台上移植UB37星闪模块驱动的完整流程,涵盖内核配置、设备树适配、驱动编译、功能测试等关键步骤。通过实践指导,帮助开发者掌握星闪技术在嵌入式系统中的集成与应用,提升无线通信模块的开发效率。

qsc90123456的博客 337

一文带你搞懂APK安装过程

本篇从用户感受的APK安装讲起,分别详细梳理了 包管理器服务——PackageManagerService 的服务开启、初始化扫描过程;然后分析了对应原生系统的安装过程及页面;接着就是详细分析了安装流程,包括创建Session 发送APK、PMS中的APK拷贝操作、包括APK解析校验和dexOpt等具体安装流程;最后是安装结果的发送。内容确实很多,但是我们只需要重点了解 PMS的初始化、APK安装 的整体流程即可,无需关注繁杂的细节。

chuyouyinghe的专栏 7983

C#对接EtherNet/IP协议 完整版|罗克韦尔AB PLC通信+CIP核心概念全解析

你做罗克韦尔(AB) PLC工业上位机开发,是唯一的首选协议,没有之一!EtherNet/IP(Ethernet Industrial Protocol)是基于标准以太网的工业级通信协议,由罗克韦尔自动化主导开发,是ODVA(开放设备网络供应商协会)主推的工业以太网标准,也是目前全球应用最广泛的工业以太网协议之一。原生适配罗克韦尔AB PLC:Micro800、CompactLogix、ControlLogix、Micro850等全系AB PLC原生标配EtherNet/IP,无需额外配置,开箱即用;

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 895

一文吃透 SAP HANA Service Broker:原理、架构与落地实践

摘要:SAP HANA Service Broker 作为云原生开发的关键组件,通过标准化流程管理 HDI 容器与服务实例的生命周期,实现数据库资源的自动化配置与安全隔离。它采用服务目录、服务计划和绑定机制,将连接凭据注入应用环境变量,避免硬编码风险。在实际应用中,需根据模块生命周期决定共享或隔离容器,并通过跨容器访问模式实现安全数据共享。典型案例展示了电商平台的多模块协同与SaaS租户隔离场景,验证了其在提升运维效率与安全合规方面的价值。最佳实践强调以生命周期划边界、最小权限原则和HTTPS安全传输,为企

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 226

一文看懂Android APK安装的原理

Android APK 安装原理解析前言APK包的构成安装APK总结 前言 大家有没有想过一个应用的APK是怎么被安装到安卓手机上的,安装的本质是什么?我们知道,Windows应用程序的安装包是一个可执行的压缩包,安装的过程是把压缩包中的数据和依赖库拷贝到安装目录,再在桌面或启动栏创建快捷方式,那么安卓的APK安装过程是不是也是这样的呢?本文将为大家解答这些问题。 APK包的构成 首先,我看一下A...

好重好重的专栏 3867

EMD (经验模态分解) 在 C++ 中的实现指南

EMD 是由 Norden E. Huang 等人在1998年提出的一种适用于非线性和非平稳信号的分析方法。对称性:IMF 的上下包络对称。零交叉点:IMF 的零交叉点数量与极值点数量相同或相差一个。本文详细介绍了如何在C++中实现EMD,包括理论背景、算法步骤、代码实现和优化等内容。通过丰富的代码示例和详细的解释,希望能够帮助读者掌握EMD的基本原理,并能够在实际项目中灵活应用。未来,随着信号处理技术的不断发展,EMD及其变种(如EEMD、CEEMDAN等)将继续在各个领域发挥重要作用。

qq_38334677的博客 1750

APK安装过程及原理详解

应用程序包的安装是android的特点 APK为AndroidPackage的缩写 Android应用安装有如下四种方式: 1.系统应用安装――开机时完成,没有安装界面 2.网络下载应用安装――通过market应用完成,没有安装界面 3.ADB工具安装――没有安装界面。

Android 开发 5万+

解锁机器人动态平衡算法:从原理到实践

机器人的动态平衡,是指机器人在运动过程中,面对各种复杂的动态变化和外界干扰,依然能够维持稳定状态,不发生倾倒或失去控制的能力。它就像是一位技艺精湛的舞者,在舞台上翩翩起舞时,无论做出多么复杂的动作,都能巧妙地调整身体姿态,始终保持平衡,展现出优美的舞姿。在实际应用中,机器人的动态平衡对于其稳定运行起着至关重要的作用。以双足机器人为例,当它行走在不平整的地面上时,地面的起伏会使机器人的重心不断发生变化。如果没有良好的动态平衡能力,机器人就很容易因为重心偏移而摔倒,无法完成行走任务。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 3838

YOLOv8【第十章:多任务扩展深度篇·第18节】不规则工业缺陷分割——针对划痕、裂纹的 Seg 模型调优!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。

**My Coding Family** 3982

Android APK安装过程及原理详解

FROM:http://blog.youkuaiyun.com/hdhd588/article/details/6739281 ============================================================= 应用程序包的安装是android的特点 APK---AndroidPackage Android

·没有风雨躲得过,没有坎坷不必走· 2万+

[网络安全提高篇] 一二〇.恶意软件动态分析经典沙箱Cape批量提取动态API特征

这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。前文详细介绍动态分析沙箱Cape的安装过程,其是一个开源的自动恶意软件分析系统,通过自动运行和分析恶意软件,全面分析和提取恶意软件的关键特征。然而,当样本数量增加时,单个样本分析会降低效率。这篇文章将讲解如何实现Cape沙箱的批量分析,通过调用Python脚本文件来实施批量处理,并将分析结果存储在指定位置,最后补充submit.py的参数及Python调用方式。基础性文章,希望对您有帮助!

杨秀璋的专栏 4123

Android APK 安装过程及原理详解

应用程序包的安装是android的特点 APK为AndroidPackage的缩写 Android应用安装有如下四种方式: 1.系统应用安装――开机时完成,没有安装界面 2.网络下载应用安装――通过market应用完成,没有安装界面 3.ADB工具安装――没有安装界面。 4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由         pack

CPP工程师的专栏 1552

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

获取android手机内外部存储空间的参数 && 如何决定一个apk的安装位置 && APK安装过程及原理详解

转载地址:http://blog.youkuaiyun.com/zhandoushi1982/article/details/8560233 获取Android文件系统的信息,需要Environment类和StatFs类的支持。 (1)Environment 是一个提供访问环境变量的类,常用的方法有:        A,getRootDirectory() ,返回File,获取Android

z469571695的专栏 1574

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

android的APK的方方面面——转载

APK安装包的内容及其安装过程原理详解—— android的小菜鸟

Mocarcher的博客 258

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Android中APK安装过程及原理解析

应用安装是智能机的主要特点,即用户可以把各种应用(如游戏等)安装到手机上,并可以对其进行卸载等管理操作。APK是Android Package的缩写,即Android安装包。APK是类似Symbian Sis或Sisx的文件格式。通过将APK文件直接传到Android模拟器或Android手机中执行即可安装。Android应用安装有如下四种方式1.系统应用安装――开机时完成,没有安装界面2.网络下

fishmai的专栏 4197

Android应用安装过程及原理

Android应用安装的流程及路径: 应用安装涉及到如下几个目录: system/app 系统自带的应用程序,无法删除 data/app 用户程序安装的目录,有删除权限。安装时把apk文件复制到此目录 data/data 存放应用程序的数据 Data/dalvik-cache ...

grandself的博客 1万+

Android Apk安装原理

APK安装分为有界面安装和无界面安装 有界面安装 UI界面在packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java 来看下PackageInstallerActivity (Android7.0.0_r31) 然后,通过PackageUtil.getPackag...

朱豪凯的博客 1541

android备份:apk安装过程及原理,备份已安装应用的apk包技术实现方案

安卓设备上备份已安装应用的apk包技术实现方案需求的目的在只有安装应用, 没有该应用的apk,而我们又想活取应用apk,用来分享给别人,或是应用的备份, 说是应用的增量升级的, 怎么办?本文将告诉你如何靠谱的导出一个已安装应用的apk.了解相关目录安卓设备上根据安卓方式的不同,安装的数据存放路径也不同1. system/app此类应用是系统初始化时候安装完成的, 存放在 ‘system/app’ ...

weixin_36123300的博客 2851

Android中apk安装过程源码解析

android apk安装流程源码解析

k663514387的博客 3870
上一篇: Android——PackageManager
下一篇: Android——APK 安装位置管理
南丶烟
博客等级 码龄14年 569粉丝 98原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值