Android9.0 静默安装源码的实现

网上基本都停在8.0就没人开始分析Android9.0如何静默apk的代码,这是我自己之前研究9.0的framework整理出来的,真实源码整理

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 作者 :
 * 邮箱 : 709847739#qq.com
 * 时间  : 2019/2/21-9:21
 * desc  :
 * version: 1.0
 */
public class PackageManagerCompatP {

  private final static String TAG = PackageManagerCompatP.class.getSimpleName();

  public static final long MAX_WAIT_TIME = 25 * 1000;

  public static final long WAIT_TIME_INCR = 5 * 1000;

  private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec";

  private Context mContext;

  public PackageManagerCompatQ(Context context) {
    this.mContext = context;
  }

  private static class LocalIntentReceiver {
    private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();

    private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
      @Override
      public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
               IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
        try {
          mResult.offer(intent, 5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        }
      }
    };

    public IntentSender getIntentSender() {
      Class<?> aClass = null;
      try {
        aClass = Class.forName("android.content.IntentSender");
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      }
      if (aClass == null) {
        return null;
      }
      try {
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
          Log.i(TAG, "declaredConstructor.toString():" + declaredConstructor.toString());
          Log.i(TAG, "declaredConstructor.getName():" + declaredConstructor.getName());
          Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
          for (Class<?> parameterType : parameterTypes) {
            Class aClass1 = parameterType.getClass();
            Log.i(TAG, "parameterTypes...aClass1:" + aClass1.getName());
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
      Constructor constructor = null;
      try {
        constructor = aClass.getDeclaredConstructor(IIntentSender.class);
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      }
      if (constructor == null) {
        return null;
      }
      Object o = null;
      try {
        o = constructor.newInstance((IIntentSender) mLocalSender);
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InstantiationException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
      return (IntentSender) o;
//         new IntentSender((IIntentSender) mLocalSender)
    }

    public Intent getResult() {
      try {
        return mResult.take();
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
    }
  }

  private PackageManager getPm() {
    return mContext.getPackageManager();
  }

  private PackageInstaller getPi() {
    return getPm().getPackageInstaller();
  }

  private void writeSplitToInstallSession(PackageInstaller.Session session, String inPath,
                      String splitName) throws RemoteException {
    long sizeBytes = 0;
    final File file = new File(inPath);
    if (file.isFile()) {
      sizeBytes = file.length();
    } else {
      return;
    }

    InputStream in = null;
    OutputStream out = null;
    try {
      in = new FileInputStream(inPath);
      out = session.openWrite(splitName, 0, sizeBytes);

      int total = 0;
      byte[] buffer = new byte[65536];
      int c;
      while ((c = in.read(buffer)) != -1) {
        total += c;
        out.write(buffer, 0, c);
      }
      session.fsync(out);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      IoUtils.closeQuietly(out);
      IoUtils.closeQuietly(in);
      IoUtils.closeQuietly(session);
    }
  }

  /**
   * 入口方法
   * String apkPackageName = ""; //填写安装的包名
   * String apkPath = "";//填写安装的路径
   **/
  public void testReplaceFlagSdcardInternal(String apkPackageName, String apkPath) throws Exception {
    // Do not run on devices with emulated external storage.
    if (Environment.isExternalStorageEmulated()) {
      return;
    }

    int iFlags = 0x00000008;// PackageManager.INSTALL_EXTERNAL 0x00000008
    int rFlags = 0;
    //这个暂时用不上
    //InstallParams ip = sampleInstallFromRawResource(iFlags, false);
    Uri uri = Uri.fromFile(new File(apkPath));
    GenericReceiver receiver = new ReplaceReceiver(apkPackageName);
    int replaceFlags = rFlags | 0x00000002;//PackageManager.INSTALL_REPLACE_EXISTING 0x00000002
    try {
      invokeInstallPackage(uri, replaceFlags, receiver, true);
      //assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
    } catch (Exception e) {
      Log.e(TAG, "Failed with exception : " + e);
    } finally {
//      cleanUpInstall(ip);
    }
  }

//  class InstallParams {
//    Uri packageURI;
//
//    PackageParser.Package pkg;
//
//    InstallParams(String outFileName, int rawResId) throws PackageParserException {
//      this.pkg = getParsedPackage(outFileName, rawResId);
//      this.packageURI = Uri.fromFile(new File(pkg.codePath));
//    }
//
//    InstallParams(PackageParser.Package pkg) {
//      this.packageURI = Uri.fromFile(new File(pkg.codePath));
//      this.pkg = pkg;
//    }
//
//    long getApkSize() {
//      File file = new File(pkg.codePath);
//      return file.length();
//    }
//  }
//
//  private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp)
//      throws Exception {
//    return installFromRawResource("install.apk", android.R.raw.install, flags, cleanUp, false, -1,
//        PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
//  }

//  private void cleanUpInstall(InstallParams ip) {
//
//  }

  private void cleanUpInstall(String pkgName) throws Exception {
    if (pkgName == null) {
      return;
    }
    Log.i(TAG, "Deleting package : " + pkgName);
    try {
      final ApplicationInfo info = getPm().getApplicationInfo(pkgName,
          PackageManager.MATCH_UNINSTALLED_PACKAGES);
      if (info != null) {
        //PackageManager.DELETE_ALL_USERS
        final LocalIntentReceiver localReceiver = new LocalIntentReceiver();
        //这是卸载,不调用
//        getPi().uninstall(pkgName,
//            0x00000002,
//            localReceiver.getIntentSender());
        localReceiver.getResult();
        assertUninstalled(info);
      }
    } catch (IllegalArgumentException | PackageManager.NameNotFoundException e) {
      e.printStackTrace();
    }
  }

  private static void assertUninstalled(ApplicationInfo info) throws Exception {
    File nativeLibraryFile = new File(info.nativeLibraryDir);
    Log.e(TAG, "Native library directory " + info.nativeLibraryDir
        + " should be erased" + nativeLibraryFile.exists());
  }

  private void invokeInstallPackage(Uri packageUri, int flags, GenericReceiver receiver,
                   boolean shouldSucceed) {
    mContext.registerReceiver(receiver, receiver.filter);
    synchronized (receiver) {
      final String inPath = packageUri.getPath();
      PackageInstaller.Session session = null;
      try {
        final PackageInstaller.SessionParams sessionParams =
            new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        try {
          //sessionParams.installFlags = flags;
          Field installFlags = sessionParams.getClass().getDeclaredField("installFlags");
          installFlags.set(sessionParams, flags);
        } catch (NoSuchFieldException e) {
          e.printStackTrace();
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
        final int sessionId = getPi().createSession(sessionParams);
        session = getPi().openSession(sessionId);
        writeSplitToInstallSession(session, inPath, "base.apk");
        final LocalIntentReceiver localReceiver = new LocalIntentReceiver();
        session.commit(localReceiver.getIntentSender());
        final Intent result = localReceiver.getResult();
        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
            PackageInstaller.STATUS_FAILURE);
        if (shouldSucceed) {
          if (status != PackageInstaller.STATUS_SUCCESS) {
            Log.e(TAG, "Installation should have succeeded, but got code " + status);
          }
        } else {
          if (status == PackageInstaller.STATUS_SUCCESS) {
            Log.e(TAG, "Installation should have failed");
          }
          // We'll never get a broadcast since the package failed to install
          return;
        }
        // Verify we received the broadcast
        long waitTime = 0;
        while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
          try {
            receiver.wait(WAIT_TIME_INCR);
            waitTime += WAIT_TIME_INCR;
          } catch (InterruptedException e) {
            Log.i(TAG, "Interrupted during sleep", e);
          }
        }
        if (!receiver.isDone()) {
          Log.e(TAG, "Timed out waiting for PACKAGE_ADDED notification");
        }
      } catch (IllegalArgumentException | IOException | RemoteException e) {
        Log.e(TAG, "Failed to install package; path=" + inPath, e);
      } finally {
        IoUtils.closeQuietly(session);
        mContext.unregisterReceiver(receiver);
      }
    }
  }

  private abstract static class GenericReceiver extends BroadcastReceiver {
    private boolean doneFlag = false;

    boolean received = false;

    Intent intent;

    IntentFilter filter;

    abstract boolean notifyNow(Intent intent);

    @Override
    public void onReceive(Context context, Intent intent) {
      if (notifyNow(intent)) {
        synchronized (this) {
          received = true;
          doneFlag = true;
          this.intent = intent;
          notifyAll();
        }
      }
    }

    public boolean isDone() {
      return doneFlag;
    }

    public void setFilter(IntentFilter filter) {
      this.filter = filter;
    }
  }

  class ReplaceReceiver extends GenericReceiver {
    String pkgName;

    final static int INVALID = -1;

    final static int REMOVED = 1;

    final static int ADDED = 2;

    final static int REPLACED = 3;

    int removed = INVALID;

    // for updated system apps only
    boolean update = false;

    ReplaceReceiver(String pkgName) {
      this.pkgName = pkgName;
      filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
      filter.addAction(Intent.ACTION_PACKAGE_ADDED);
      if (update) {
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
      }
      filter.addDataScheme("package");
      super.setFilter(filter);
    }

    public boolean notifyNow(Intent intent) {
      String action = intent.getAction();
      Uri data = intent.getData();
      String installedPkg = data.getEncodedSchemeSpecificPart();
      if (pkgName == null || !pkgName.equals(installedPkg)) {
        return false;
      }
      if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
        removed = REMOVED;
      } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
        if (removed != REMOVED) {
          return false;
        }
        boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
        if (!replacing) {
          return false;
        }
        removed = ADDED;
        if (!update) {
          return true;
        }
      } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
        if (removed != ADDED) {
          return false;
        }
        removed = REPLACED;
        return true;
      }
      return false;
    }
  }

}

就这一个类的封装,我也是看framework扣出来的

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android程序静默安装安装后重新启动APP的方法

     一:需求简介 之前boss提出一个需求,运行在广告机上的app,需要完成自动升级的功能,广告机是非触摸屏的,不能通过手动点击,所以app必须做到自动下载,自动安装升级,并且安装完成后,app还要继续运行,最好不借助其它app来实现以上功能.  二:实现思路 实现这个功能第一个想到的方法就是静默安装,由于广告机已经root,静默安装比较顺利,安装app的主要代码如下: /* @pararm apkPath 等待安装的app全路径,如:/sdcard/app/app.apk **/ private

  • Android静默安装实现方案 仿360手机助手秒装和智能安装功能

    之前有很多朋友都问过我,在Android系统中怎样才能实现静默安装呢?所谓的静默安装,就是不用弹出系统的安装界面,在不影响用户任何操作的情况下不知不觉地将程序装好.虽说这种方式看上去不打搅用户,但是却存在着一个问题,因为Android系统会在安装界面当中把程序所声明的权限展示给用户看,用户来评估一下这些权限然后决定是否要安装该程序,但如果使用了静默安装的方式,也就没有地方让用户看权限了,相当于用户被动接受了这些权限.在Android官方看来,这显示是一种非常危险的行为,因此静默安装这一行为系统是

  • Android 静默安装和智能安装的实现方法

    1 简介 最近研究了Android的静默安装和智能安装,于是写博客记录一下.静默安装就是无声无息的在后台安装apk,没有任何界面提示.智能安装就是有安装界面,但全部是自动的,不需要用户去点击. 首先强调两点:静默安装必须要root权限 智能安装必须要用户手动开启无障碍服务 2 原理 静默安装.卸载的原理就是利用pm install命令来安装apk,pm uninstall 来卸载apk. 智能安装是利用android系统提供的无障碍服务AccessibilityService,来模拟用户点击,从

  • Android 静默安装实现方法

    Android静默安装的方法,静默安装就是绕过安装程序时的提示窗口,直接在后台安装. 注意:静默安装的前提是设备有ROOT权限. 代码如下: /** * 静默安装 * @param file * @return */ public boolean slientInstall(File file) { boolean result = false; Process process = null; OutputStream out = null; try { process = Runtime.ge

  • Android实现静默安装的两种方法

    前言 一般情况下,Android系统安装apk会出现一个安装界面,用户可以点击确定或者取消来进行apk的安装. 但在实际的项目需求中,有一种需求,就是希望apk在后台安装(不出现安装界面的提示),这种安装方式称为静默安装.下面这篇文章就给大家介绍了两种方法来实现,下面来一起看看吧. 1.root权限静默安装实现 实现实际使用的是su pm install -r filePath命令. 核心代码如下: protected static void excuteSuCMD() { Process pr

  • Android无需root实现apk的静默安装

    Android的静默安装似乎是一个很有趣很诱人的东西,但是,用普通做法,如果手机没有root权限的话,似乎很难实现静默安装,因为Android并不提供显示的Intent调用,一般是通过以下方式安装apk: Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); startAct

  • android实现静默安装与卸载的方法

    本文实例讲述了android实现静默安装与卸载的方法.分享给大家供大家参考.具体如下: 方法1:[使用调用接口方法,由于安装卸载应用程序的部分API是隐藏的,所以必须下载Android系统源码,在源码下开发并编译之后使用MM命令编译生成APK文件] import java.io.File; import android.app.Activity; import android.os.Bundle; import android.content.Intent; import android.con

  • Android实现静默安装实例代码

    静默安装主要分为以下几种方式: 一.在ROOT过的机器上,在App中使用pm install指令安装APK: // 申请su权限 Process process = Runtime.getRuntime().exec("su"); dataOutputStream = new DataOutputStream(process.getOutputStream()); // 执行pm install命令 String command = "pm install -r "

  • Android 静默安装和卸载的方法

    本文介绍了Android 静默安装和卸载的方法,分享给大家,具体如下: 一. 条件 系统签名 需要放到 /system/app里作为系统app 二. 适用环境 机顶盒开发,系统开发,车机开发,智能设备开发. 三. 步骤 1. 在 AndroidManifest.xml 中 1.1. 在清单文件 AndroidManifest.xml 添加 android.uid.system 声明为系统应用. 1.2. 权限 <uses-permission android:name="android.p

  • Android9.0 静默安装源码的实现

    网上基本都停在8.0就没人开始分析Android9.0如何静默apk的代码,这是我自己之前研究9.0的framework整理出来的,真实源码整理 import android.content.BroadcastReceiver; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.In

  • thinkphp3.2.0 setInc方法 源码全面解析

    我们先来看一下setInc的官方示例: 需要一个字段和一个自增的值(默认为1) 我们通过下面这个例子来一步步分析他的底层是怎么实现的: <?php namespace Home\Controller; use Think\Controller; class TestController extends Controller { public function test() { $tb_test = M('test'); $tb_test->where(['id'=>1])->set

  • Backbone.js 0.9.2 源码注释中文翻译版

    // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone may be freely distributed under the MIT license. // For all details and documentation: // http://backbonejs.org (function() { // 创建一个全局对象, 在浏览器中表示为window对象, 在Node.j

  • linux常用命令小结之yum、源码安装

    一.软件安装 rpm rpm -ivh zziplib-0.13.62-5.el7.x86_64.rpm   //安装zziplib-0.13.62-5.el7.x86_64.rpm rpm  -qf `which cd`      //查看cd的包名,这里使用反引号,rpm会取反引号中命令的结果作为参数, rpm包格式,包名.版本号.发布版本号.平台 rpm -ivh rpm包文件 //安装 rpm -Uvh rpm包文件 //升级 rpm -e 包名 //卸载 rpm -qa //查询安装的

  • MAC下基于maven使用IDEA走读TestNG源码解析

    之前用Python执行程序都是python xxx.py,最近在使用Java技术栈的TestNG,于是想能够也用命令行实现- 创建一个Maven项目 确保已安装了Maven,可使用Maven命令后,使用以下命令可快速创建Maven项目 mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeV

  • 解析Linux源码之epoll

    目录 一.前言 二.简单的epoll例子 2.1.epoll_create 2.2.struct eventpoll 2.3.epoll_ctl(add) 2.4.ep_insert 2.5.tfile->f_op->poll的实现 2.6.回调函数的安装 2.7.epoll_wait 2.8.ep_send_events 三.事件到来添加到epoll就绪队列(rdllist)的过程 3.1.可读事件到来 3.2.可写事件到来 四.关闭描述符(close fd) 五.总结 一.前言 在linu

  • Bootstrap源码解读导航条(7)

    源码解读Bootstrap导航条 基础导航条 要制作一个基础导航条,要在制作导航的列表<ul class="nav">基础上添加类名"navbar-nav",然后在列表外部添加一个容器(div),并且使用类名"navbar"和"navbar-default".例如: <div class="navbar navbar-default" role="navigation"

  • 基于Spring Boot的Environment源码理解实现分散配置详解

    前提 org.springframework.core.env.Environment是当前应用运行环境的公开接口,主要包括应用程序运行环境的两个关键方面:配置文件(profiles)和属性.Environment继承自接口PropertyResolver,而PropertyResolver提供了属性访问的相关方法.这篇文章从源码的角度分析Environment的存储容器和加载流程,然后基于源码的理解给出一个生产级别的扩展. 本文较长,请用一个舒服的姿势阅读. Environment类体系 Pr

  • Nginx源码研究之nginx限流模块详解

    高并发系统有三把利器:缓存.降级和限流: 限流的目的是通过对并发访问/请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务(定向到错误页).排队等待(秒杀).降级(返回兜底数据或默认数据): 高并发系统常见的限流有:限制总并发数(数据库连接池).限制瞬时并发数(如nginx的limit_conn模块,用来限制瞬时并发连接数).限制时间窗口内的平均速率(nginx的limit_req模块,用来限制每秒的平均速率): 另外还可以根据网络连接数.网络流量.CPU或内存负载等来限流. 1.限流算法 最

  • C++11 shared_ptr 与 make_shared源码剖析详解

    目录 0. 前言 1. 源码分析 1.1 头文件 1.2 构造 1.2.1 shared_ptr 的移动构造函数 1.2.2 shared_ptr 的拷贝构造函数 1.3 赋值重载 1.4 修改的接口 1.5 获取 2. make_shared 2.1 make_shared 优点 2.1.1 效率高 2.1.2 异常安全 2.2 make_shared缺点 3. 举例 参考: 总结 0. 前言 所谓智能指针,可以从字面上理解为"智能"的指针.具体来讲,智能指针和普通指针的用法是相似的

随机推荐