MTK-Android13-包安装器PackageInstaller 静默安装实现

目的

  • 我们最终是为了搞明白安装的整个流程。一方面通过安卓系统自带的包安装器来了解PMS 安装流程;另一方面熟悉框架层Framework 针对Android apk 安装流程。

前两篇文章分析了PackagerInstaller 安装流程。 Android13-包安装器PackageInstaller-之apk安装跳转
Android13-包安装器PackageInstaller-之apk安装流程
后面空了再分析框架层PMS的处理以及在框架层面的少许拦截和加功能。

  • 实现需求定制:静默安装-安装界面定制-安装拦截验证。【核心目的】

安装流程和PMS了解不用多说了; 安装定制相关:

  • 手机上安装时候弹出锁屏界面需要输入密码;
  • 安装时候弹出密码框,让用户输入定制的特殊密码功能;
  • 安装页面客制化需求

安装方式

当然正常的安装分为类型我其实理解为大概3种

  • 无界面安装:PMS启动阶段 比如系统第一次启动,所有内置app自动批量安装;我们重试系统app开发时候,或者内置系统apk开发时候,删除对应的目录下的apk和apk对应的/data/分区下的apk所有安装信息后,push
    更新的apk到系统,重启。 apk 自动重新安装。

  • adb 安装: adb 命令安装,通过adb install 安装,依托守护进程来实现安装

  • 点击安装或者调用方法安装:应用市场再下载完apk后自动进入进入包管理器进行安装;sd开或者外部存储中的安装包点击安装自动进入包管理器进行安装

相关资料推荐;

PackageInstaller的初始化

PackageInstaller安装APK

PMS处理APK的安装

PMS的创建过程
APK 安装流程

安装过程 界面跳转
Apk的安装过程探究
Android11.0系统中实现静默安装并启动App以及静默卸载

静默安装实现

修改文件

添加文件:

frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/SilenceInstallReceiver.java
frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/SilenceInstallManager.java

修改文件:

frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerApplication.java
frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
frameworks/base/packages/PackageInstaller/AndroidManifest.xml
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

实现思路

按照前两篇PackageInstaller 包管理器 了解的安装流程和思路,实现方案总结以下两点:

  • 延用现有的所有PackagerInstaller 逻辑,在判断安装地方 一路静默,默认同意。【弊端 涉及到多个Activity,特别是安装流程,等待都是花时间的,造成界面App假死】
  • 将所有的安装逻辑放到第一个InstallStart Activity里面,对Activity实现,在Activity 里面进行异步处理,同时对Activity进行返回后台。 【不要影响界面上面正在操作的App】
  • 在跳转到InstallStart Activity后,跳转到Service 里面处理,结束当前Activity 即可,这样安装逻辑就在Service 里面了。

实现具体方案

这里列举在 InstallStart Activity 里面进行逻辑处理,作为一个方案的引入。 实际项目中直接在Service里面处理的。

SilenceInstallReceiver

新增的一个安装成功监听、通知显示提示,根据自身需要是否需要,进行定制或直接删除。


public class PackageInstalledReceiver extends BroadcastReceiver {
   
    private static final String TAG = PackageInstalledReceiver.class.getSimpleName();

    private static final boolean DEBUG = false;

    @Override
    public void onReceive(Context context, Intent intent) {
   
        if (Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, 0) == 0) {
   
            return;
        }

        String action = intent.getAction();

        if (DEBUG) {
   
            Log.i(TAG, "Received action: " + action);
        }

        if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
   
            Uri packageUri = intent.getData();
            if (packageUri == null) {
   
                return;
            }

            String packageName = packageUri.getSchemeSpecificPart();
            if (packageName == null) {
   
                Log.e(TAG, "No package name");
                return;
            }

            if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
   
                if (DEBUG) {
   
                    Log.i(TAG, "Not new app, skip it: " + packageName);
                }
                return;
            }

            // TODO: Make sure the installer information here is accurate
            String installer =
                    context.getPackageManager().getInstallerPackageName(packageName);
            new PackageInstalledNotificationUtils(context, installer,
                    packageName).postAppInstalledNotification();
        }
    }
}	
   

SilenceInstallManager

静默安装的核心工具类,做了以下几个工作,针对PackageInstall 安装流程进行了一个提取
  • copy 文件,安装包文件拷贝
  • session 的创建、注册回调、交互,安装工作提交到Framework层 commit 、registerSessionCallback(mSessionCallback)
  • 这里封装了静默安装和卸载的方法

PackageInstallerApplication.java

Application 中初始化工具类
	SilenceInstallManager.getInstance(this);

UninstallerActivity.java

静默卸载方案实现,调用工具类方法

 onCreate 方法中 
 if (intent.getBooleanExtra(SilenceInstallReceiver.SILENCE_INSTALL_KEY, false)) {
   
			 Log.d(TAG, "silenceUninstall ....");
            SilenceInstallManager.getInstance(this).silenceUninstall(mPackageName);
            return;
 }
	

InstallStart

内部创建一个异步线程

   // if silence install  ->to silence install 
        if (intent.getBooleanExtra(SilenceInstallReceiver.SILENCE_INSTALL_KEY, false)) {
   
			Log.d(TAG," StagingAsyncAppTask  to  execute ");
            StagingAsyncAppTask mStagingTask = new StagingAsyncAppTask(intent.getBooleanExtra(SilenceInstallReceiver.IS_LAUNCH_KEY, false));
            mStagingTask.execute(getIntent().getData());
			
            return;
        }

异步线程作什么呢?

  • 拷贝文件
  • 创建uri,发送广播 通知
@SuppressLint("NewApi")
    private final class StagingAsyncAppTask extends AsyncTask<Uri, Void, File> {
   

        private boolean mIsLaunch;

        public StagingAsyncAppTask(boolean isLaunch){
   
            mIsLaunch = isLaunch;
        }


        @Override
        protected File doInBackground(Uri... params) {
   
            Log.d(LOG_TAG, "copy file from user app start");
            if (params == null || params.length <= 0) {
   
                return null;
            }
            Uri packageUri = params[0];
            try (InputStream in = getContentResolver().openInputStream(packageUri)) {
   
                // Despite the comments in ContentResolver#openInputStream the returned stream can
                // be null.
                if (in == null) {
   
                    return null;
                }

                File mStagedFile = TemporaryFileManager.getStagedFile(InstallStart.this);

                try (OutputStream out = new FileOutputStream(mStagedFile)) {
   
                    byte[] buffer = new byte[1024 * 1024];
                    int bytesRead;
                    while ((bytesRead = in.read(buffer)) >= 0) {
   
                        // Be nice and respond to a cancellation
                        out.write(buffer, 0, bytesRead);
                    }
                }
                return mStagedFile;
            } catch (IOException | SecurityException | IllegalStateException e) {
   
                Log.w(LOG_TAG, "Error staging apk from content URI", e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(File installFile) {
   
            if (null != installFile) {
   
                // Now start the installation again from a file
                Log.d(LOG_TAG, "copy file from user app finish");

                Intent installIntent = new Intent(SilenceInstallReceiver.SILENCE_INSTALL_APP);
                installIntent.putExtra(SilenceInstallReceiver.APP_URI_KEY, Uri.fromFile(installFile)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值