最近弄项目都是些要改源码才能实现的,像静默安装和白名单功能.

静默安装:

1:在源码的AndroidMainfest.xml中添加权限

--- a/frameworks/base/core/res/AndroidManifest.xml
+++ b/frameworks/base/core/res/AndroidManifest.xml
@@ -2451,6 +2451,10 @@
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INSTALL_PACKAGES"
         android:protectionLevel="signature|privileged" />
+    <permission android:name="android.permission.HIDE_INSTALL_PACKAGES"
+        android:protectionLevel="normal" />
+    <permission android:name="android.permission.HIDE_UNINSTALL_PACKAGES"
+        android:protectionLevel="normal" />

2 :在IPackManger.Stub中添加权限判断

--- a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11704,7 +11704,13 @@ public class PackageManagerService extends IPackageManager.Stub {
     public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
             int installFlags, String installerPackageName, int userId) {
         android.util.SeempLog.record(90);
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+        //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+        if(mContext.checkCallingPermission(android.Manifest.permission.HIDE_INSTALL_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
+            Slog.i(TAG, "installerPackageName: checkCallingPermission "+installerPackageName);
+        } else {
+            Slog.i(TAG, "installerPackageName: checkCallingPermission PERMISSION_DENIED"+PackageManager.PERMISSION_DENIED);
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+        }

3:在APP的libs添加pminstall.jar

4:在APP中添加<uses-permission android:name="android.permission.HIDE_INSTALL_PACKAGES" />权限

静默安装就成功了!!!撒花庆祝。

demo的连接地址:https://github.com/ChloeDimen/pmApplication

白名单功能:因为也是在在源码中修改,查了很多资料和自己的理解,有可能有问题。希望大家理解,有问题大家在评论中提出。

本人希望白名单是可以在SD卡中修改的,查资料是把白名单打包到系统的,所有自己修改验证。

先说下android的apk安装方式,在修改源码。

1:直接调用安装接口

  1. Uri mPackageURI = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + apkName));

  2. int installFlags = 0;

  3. PackageManager pm = getPackageManager();

  4. try{

  5. PackageInfo pi = pm.getPackageInfo(packageName,

  6. PackageManager.GET_UNINSTALLED_PACKAGES);

  7. if(pi != null) {

  8. installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;

  9. }

  10. }

  11. catch (NameNotFoundException e){}

  12. PackageInstallObserver observer = new PackageInstallObserver();

  13. pm.installPackage(mPackageURI, observer, installFlags);

这种方式一般在APP中,我们是用AIDl的集成,在调用pm.installpackage(mPackageURI, observer, installFlags)。不过要配置很多东西,AIDl导入也要很多错误,要自己修改。app还需要在AndroidManifest增加一句 android:sharedUserId=”android.uid.system”,而且还要用系统的签名工具。因为每个版本和每种不同手机的签名工具不一样,所有在手机上不适合。在市面上像完成静默安装,我知道的只有开发应用市场类的APP。

我现在可以修改源码,就是在自己的板子上开发了!!!

2:通过intent机制,调用packageInstall进行安装(有弹框)

  1. String fileName = Environment.getExternalStorageDirectory() + apkName;

  2. Uri uri = Uri.fromFile(new File(fileName));

  3. Intent intent = new Intent(Intent.ACTION_VIEW);

  4. intent.setDataAndType(Uri, application/vnd.android.package-archive");

  5. startActivity(intent)

3:通过命令进行安装 pm install

修改源码:

1:packageMangerServer修改

源码位置:frameworks\base\services\core\java\com\android\server\pm\PackageMangerServer.java,对源码不熟悉找位置找了好久(后面的现在方便了)。

1)添加函数判断

/*add for installer white list*/
    private boolean isInstallerEnable(String packagename){
        ArrayList<String> whiteListApp = new ArrayList<String>();
         Log.e(TAG, "mCallingApp:==5 " );
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
            new FileInputStream("/sdcard/WhiteListAppFilter.properties")));
                 Log.e(TAG, "mCallingApp:==6 " );
            String line ="";
            while ((line = br.readLine()) != null){
 Log.e(TAG, "mCallingApp:==7 " );
                whiteListApp.add(line);
 Log.e(TAG, "mCallingApp:==8 " );
            }

br.close();
        }catch(java.io.FileNotFoundException ex){
            return false;
        }catch(java.io.IOException ex){
            return false;
        }
          Log.e(TAG, "mCallingApp:==9 " );
        Iterator<String> it = whiteListApp.iterator();
          Log.e(TAG, "mCallingApp:==10 " );
        while (it.hasNext()) {
 Log.e(TAG, "mCallingApp:==11 " );
            String whitelisItem = it.next();
Log.e(TAG, "mCallingApp:==12 "+" ,whitelisItem"+whitelisItem+" ,packagename"+packagename );
            if (whitelisItem.equals(packagename)) {
 Log.e(TAG, "mCallingApp:==13 " );
                return true;
            }
        }
 Log.e(TAG, "mCallingApp:==14 " );
        return false;
    }

isWhiteListApp函数会去读取白名单文件/system/etc/whitelistapps,然后和我们传进来的包名进行匹配,在白名单中返回true,其他情况均返回false。这是在白名单不可以给别人修改的,我要在SD卡中"/sdcard/WhiteListAppFilter.properties"),自己修改,下面就统一这个地址。日志就不删除了,偷懒中。

重要的:要导包,查资料又是没有,苦逼。好的自己加

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import java.util.Iterator;

2)获取调用的包名判断是否在白名单中

接下来要在installPackageLI函数对调用安装的apk进行匹配,判断是否在白名单中,如果不在的话则提示错误。注释start和end的代码。

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
        final int installFlags = args.installFlags;
        String installerPackageName = args.installerPackageName;
        File tmpPackageFile = new File(args.getCodePath());
        boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
        boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
        boolean replace = false;
        final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
        // Result object to be returned
        res.returnCode = PackageManager.INSTALL_SUCCEEDED;

。。。。。。。。

try {
            pp.collectCertificates(pkg, parseFlags);
            pp.collectManifestDigest(pkg);
        } catch (PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }

//  start
        if(!isInstallerEnable(pkg.packageName)) {
            Log.e(TAG, "mCallingApp:==1 "+pkg.packageName);
            res.setError(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
                    "app is not in the whitelist. packageName:" + pkg.packageName);
Log.e(TAG, "mCallingApp:==2 " );
            return;
        }
        //  end

/* If the installer passed in a manifest digest, compare it now. */
        if (args.manifestDigest != null) {
            if (DEBUG_INSTALL) {
                final String parsedManifest = pkg.manifestDigest == null ? "null"
                        : pkg.manifestDigest.toString();
                Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
                        + parsedManifest);
            }

3)添加白名单

/system/etc/whitelistapps内容如下,在编译时可以在mk中修改拷贝到etc目录下,例如下面就是允许这三个包名有安装权限。

com.xxx.xxx1 
com.xxx.xxx2 
com.xxx.xxx3

这是在系统的可以,但在在SD卡中汇报没有权限的错误。

2、packageInstall的修改

还是参考packageManagerService的修改,增加isInstallerEnable函数,去读取白名单文件/"/sdcard/WhiteListAppFilter.properties"),然后进行包名匹配,在白名单中返回true,其他情况均返回false。

我们在packageInstaller的PackageInstallerActivity.java中增加以下修改// add for installer enable/disable ,不在白名单中的app,会直接提示不允许安装后退出。

@Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

mPm = getPackageManager();
        mInstaller = mPm.getPackageInstaller();
        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);

final Intent intent = getIntent();
        if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
            final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
            final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
            if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
                Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
                finish();
                return;
            }

。。。。。。。。

//set view
        setContentView(R.layout.install_start);
        mInstallConfirm = findViewById(R.id.install_confirm_panel);
        mInstallConfirm.setVisibility(View.INVISIBLE);
        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);

mOriginatingUid = getOriginatingUid(intent);

// add for installer enable/disable 
        if (!isInstallerEnable(mPkgInfo.packageName)) {
  Log.e(TAG, "mCallingApp:==1 " );
            //Toast.makeText(this, R.string.install_not_allow, Toast.LENGTH_LONG).show();
             this.finish();
  Log.e(TAG, "mCallingApp:==2 " );
        }

// Block the install attempt on the Unknown Sources setting if necessary.
        if (!requestFromUnknownSource) {
            initiateInstall();
            return;
        }

// If the admin prohibits it, or we're running in a managed profile, just show error
        // and exit. Otherwise show an option to take the user to Settings to change the setting.
        final boolean isManagedProfile = mUserManager.isManagedProfile();
        if (!unknownSourcesAllowedByAdmin
                || (!unknownSourcesAllowedByUser && isManagedProfile)) {
            showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
            mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
        } else if (!unknownSourcesAllowedByUser) {
            // Ask user to enable setting first
            showDialogInner(DLG_UNKNOWN_SOURCES);
            mInstallFlowAnalytics.setFlowFinished(
                    InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
        } else {
            initiateInstall();
        }
    }

/** Get the ApplicationInfo for the calling package, if available */
    private ApplicationInfo getSourceInfo() {
        String callingPackage = getCallingPackage();
        if (callingPackage != null) {
            try {
                return mPm.getApplicationInfo(callingPackage, 0);
            } catch (NameNotFoundException ex) {
                // ignore
            }
        }
        return null;
    }

3、pm install 的修改

禁止pm install,因为有些APK安装竟然是调用pm install命令去安装的。 
修改要在pm.java修改,修改方法和上面基本一致。

可以看到,pm install其实调用的是run再去判断参数。

最后还是调用

mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,

installerPackageName, verificationParams, abi, userId);

应该修改了packagemangerServer.java 就可以了。

4、在网上还找到一种方式(有带验证),不过感觉还跟简单

1.定义一些全局变量,文件位置:

Build.java (frameworks\base\core\java\android\os)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

/**

 * 包管理方式名称<br>

 *     whitelist: 白名单方式

 *     certificate: 证书认证方式

 *     none: 不进行管理

 */

public static String packageManage = "none";

/**

 * 允许 Launch 显示的 APP 及 APP 白名单

 */

public static String[] packageAllow = new String[]{ "com.baidu.searchbox",

                            "com.thinta.product.thintazlib",

                            "com.thinta.product.x4usertool"};

/**

 * 允许 Launch 显示的 APP的 证书存放路径

 */

public static String certificatePath = "/system/etc/security/media.zip";

2.修改安装APK过程,在安装过程添加验证

修改文件的位置:

PackageManagerService.java (frameworks\base\services\core\java\com\android\server\pm)

首先添加一个函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

private static HashSet<X509Certificate> getTrustedCerts(File keystore)

        throws IOException, GeneralSecurityException {

        HashSet<X509Certificate> trusted = new HashSet<X509Certificate>();

        if (keystore == null) {

            return trusted;

        }

        ZipFile zip = new ZipFile(keystore);

        try {

            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            Enumeration<? extends ZipEntry> entries = zip.entries();

            while (entries.hasMoreElements()) {

                ZipEntry entry = entries.nextElement();

                InputStream is = zip.getInputStream(entry);

                try {

                    trusted.add((X509Certificate) cf.generateCertificate(is));

                finally {

                    is.close();

                }

            }

        finally {

            zip.close();

        }

        return trusted;

    }

修改的函数:private void installPackageLI(InstallArgs args, PackageInstalledInfo res)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

第一处修改:

     if(Build.ThintaCust.packageManage.equals("certificate"))

            tmp_flags = PackageManager.GET_SIGNATURES;

        final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY

                | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)

                | (onSd ? PackageParser.PARSE_ON_SDCARD : 0) | tmp_flags;

第二处修改:

        if(Build.ThintaCust.packageManage.equals("none")){

            Log.d("XYP_DEBUG""packageManage = none  \n");

        }else if(Build.ThintaCust.packageManage.equals("whitelist")){

            Log.d("XYP_DEBUG""packageManage = whitelist  \n");

            List<String> list = Arrays.asList(Build.ThintaCust.packageAllow);

            if(list.contains(pkg.packageName)){

                Log.d("XYP_DEBUG""can install \n");

            }else{

                Log.d("XYP_DEBUG""forbid install \n");

                res.setError(PackageManager.INSTALL_FAILED_USER_RESTRICTED, "installPackageLI, forbid install");

                return;

            }

        }else if(Build.ThintaCust.packageManage.equals("certificate")){

            int verify_pass = 0;

            try{

                File file = new File(Build.ThintaCust.certificatePath);

                HashSet<X509Certificate> trusted = getTrustedCerts(file);

                CertificateFactory cf = CertificateFactory.getInstance("X.509");

                for (X509Certificate c : trusted) {

                    String tmp_public_key = c.getPublicKey().toString();

                    for(Signature sig : pkg.mSignatures)

                    {

                        X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(sig.toByteArray()));

                        String tmp_key = cert.getPublicKey().toString();

                        if(tmp_public_key.equals(tmp_key)){

                            verify_pass = 1;

                            break;

                        }

                    }

                    if(verify_pass == 1)

                        break;

                }

                if(verify_pass != 1){

                    Log.d("XYP_DEBUG""forbid install \n");

                    res.setError(PackageManager.INSTALL_FAILED_USER_RESTRICTED, "installPackageLI, forbid install");

                    return;

                }

            }catch(FileNotFoundException e){

                Log.d("XYP_DEBUG", e.toString());

            }catch(CertificateException e){

                Log.d("XYP_DEBUG", e.toString());

            }catch(IOException e){

                Log.d("XYP_DEBUG", e.toString());

            }catch(GeneralSecurityException e){

                Log.d("XYP_DEBUG", e.toString());

            }

        }

3.证书的压缩方式:

zip -r media.zip media.x509.pem

直接用命令把*.x509.pem 打包成zip文件,然后放到目标板的合适位置;

用第一步中的certificatePath指向存放该zip文件的位置。

总结:只适合自己开发板,正式版本可能有问题(比如在PackageMangerserver把白名单放在SD卡中,没有读写权限)不适合手机的方式。后续看可以解决吗??

Android 5.1.1源码修改添加白名单和静默安装功能相关推荐

  1. android 4.0模拟器启动不了,Android 4.0 framework源码修改编译,模拟器运行不起来,求助...

    当前位置:编程学习 > wap >> Android 4.0 framework源码修改编译,模拟器运行不起来,求助 我下载编译了android 4.0 ICS的源码,然后能利用编译 ...

  2. 【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )

    文章目录 安卓直播推流专栏博客总结 一. RTMP 协议 二. RTMP 协议使用 三. RTMPDump 源码下载 四. RTMPDump 源码交叉编译 五. RTMPDump 源码导入 Andro ...

  3. Android开发让用户开白名单,Android 添加白名单实现保活

    Android 白名单保活 最近有遇到保活的需求,一开始想到的就是之前的黑科技保活比如像素Activity,播放无声MP3,双进程等方法,但是随着Android系统的更新,这些非常规的方法或多或少都已 ...

  4. Android Dialer,Mms,Contacts源码修改笔记,移动端混合开发经验

    ②在AndroidManifest.xml中修改相应Activity的theme <activity android:name=".HomeActivity" android ...

  5. android系统源码中添加app源码(源码部署移植)

    涉及到系统定制,需要在系统中加入自己的apk工程,但是上网找了很多资料都是不够全面的,或者看了还是没搞懂,我自己也是一点点摸索过来的,花了不少的时间,也是踩了不少的坑,因此特开一文,帮助大家渡河. 申 ...

  6. android打开volte代码,Android8.1 源码修改之插入SIM卡默认启用Volte功能

    前言 公用电话产品,插入SIM卡后要求自动打开Volte功能,即插即用,用完拔卡就走 实现 第一步 开关对应的代码 通过打印日志和全局查找,源码位置 vendor/mediatek/proprieta ...

  7. Android系统定制源码修改 - MTK平台

                                         Android系统定制源码修改 -  MTK平台  1.修改开机弹出欢迎使用SIM MTK工程/mediatek/packag ...

  8. Android TV 源码修改默认输入法

    前一阵子,应泰国客户需求,需要在Android TV系统定制一个多语言输入法,至少支持中.英.泰三种语言.拿到这个任务,对于至今还是小白的我来说,当然先去google一下有没有大神专门做过符合要求的输 ...

  9. Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮...

    Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮 前言 之前写过屏蔽系统导航栏功能的文章,具体可看Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP) ...

最新文章

  1. seq2seq编码器和解码器:TensorFlow实现
  2. 【渝粤题库】国家开放大学2021春2238个案工作题目
  3. 前端字符串内HTML标签无效的处理方式
  4. Visual studio 2012 ultimate 安装遇到 Prerequisites , 错误的函数 incorrect function
  5. thinkphp仿百度文库网站源码
  6. MBTI性格类型测试
  7. 抑制过拟合的方法之Dropout(随机删除神经元)
  8. tomcat启动后,页面浏览时报错 Unable to compile class for JSP的解决方案
  9. 深入学习 Intellij IDEA 调试技巧
  10. Facebook再遭黑客攻击 部分账户密码被盗
  11. 功能扩展——邮件发送、网页注册
  12. fastlane build 版本号自增
  13. 即时聊天工具混战中国
  14. 数字图像处理与Python实现-Scikit-Image-图像滤波(三)
  15. unity 扩展器添加脚本
  16. ArcGIS基础:全站仪或RTK采集的DAT文件生成点图形
  17. Tomcat DBCP连接池导致的线程阻塞问题
  18. Python识别垃圾邮件
  19. 【NLP基础】常见的距离公式说明
  20. 怎么录制教学视频?这两招解决你的录屏需求

热门文章

  1. JDK内置注解元注解++反射
  2. 达梦数据库恢复到指定时间点
  3. linux系统php连接dm达梦
  4. 欢迎广大编程爱好者为MyPage网站提供改进方案
  5. 2050热身赛 1001 1004
  6. 做电商网站如何选购云服务器?
  7. 夜神模拟器连接loaclhost
  8. 框架和平台的区别以及两者的重要性(出自“至简李云” 博客)
  9. Rasa课程、Rasa培训、Rasa面试、Rasa实战系列之Understanding Rasa Deployments Premade Rasa Containers
  10. DATEADD() 函数详细说明