Android13针对APP进程修改设备Build的产品信息

1.需求来源

    有些APP在特定的设备上会有不一样的行为和显示效果,我们们如果是AOSP开发,想让它在自己的设备上也有同样的行为和显示效果,可以修改Build.java中的static final字段来满足要求。我们以Android13为例。

2.实现

    在Build.java中提供的产品信息字段基本都是static final修饰的常量或者String类型:

    /** The name of the overall product. */
    public static final String PRODUCT = getString("ro.product.name");

    /** The name of the industrial design. */
    public static final String DEVICE = getString("ro.product.device");

    /** The name of the underlying board, like "goldfish". */
    public static final String BOARD = getString("ro.product.board");

    正常是无法被直接修改,但是可以通过反射修改,在系统开发中我们可以在zygote中fork进程后去尽可能早的反射修改它。我们来看下普通APP进程的启动过程:

     Android系统中Build类的static final字段是在Zygote主进程起来时被初始化的,后面fork出的子进程不会再重新赋值,除非在子进程的生命周期方法内才去调用这些字段。从ZygoteInit中的preloads中移除Build类也是没用的,Zygote进程本身有很多地方用到了Build类,也会被它加载。

    我们只能在fork子进程之后尽可能早的去修改,如果在zygote进程修改了可能会影响到别的进程的,我们就选在子进程fork后的com.android.internal.os.Zygote#childMain方法中:

...
...
        if (args == null) {
            throw new AssertionError("Empty command line");
        }
        //这里判断APP进程的包名,做出相关修改
        if ("com.xxx.aaa".equals(args.mPackageName)){
            setupBuildInfo("BRAND", "Google");
            setupBuildInfo("DEVICE", "xxx");
            setupBuildInfo("MANUFACTURER", "Google");
            setupBuildInfo("MODEL", "hahahahh");
            setupBuildInfo("PRODUCT", "yyyyy");
        }
...
...

    setupBuildInfo方法实现:

    private static void setupBuildInfo(String field, Object value){
        try {
            // BRAND
            Field oldField = Build.class.getDeclaredField(field);
            final int mod = oldField.getModifiers();
            //设置字段可访问,public修饰的可以不用这步
            oldField.setAccessible(true);
            Log.d(TAG, "setupBuildInfo: "+field+"  "+value+", mode="+mod+", isFinal="+ Modifier.isFinal(mod));
            //去除final修饰,否则static final修饰的常量无法修改
            Field modifier = Field.class.getDeclaredField("accessFlags");
            modifier.setAccessible(true);
            modifier.setInt(oldField, mod & ~Modifier.FINAL);
            // 重新赋值
            oldField.set(null, value);
        }catch (Exception e){
            Log.e(TAG, "", e);
        }
    }

    测试效果:

   939   939 D Zygote  : Forked child process 9536
  9536  9536 D Zygote  : childMain: niceName=com.xxx.aaa, package=com.xxx.aaa, pid=9536, mInvoke=null
  9536  9536 D Zygote  : setupBuildInfo: BRAND  Google, mode=25, isFinal=true
  9536  9536 D Zygote  : setupBuildInfo: DEVICE  xxx, mode=25, isFinal=true
  9536  9536 D Zygote  : setupBuildInfo: MANUFACTURER  Google, mode=25, isFinal=true
  9536  9536 D Zygote  : setupBuildInfo: MODEL  hahahahh, mode=25, isFinal=true
  9536  9536 D Zygote  : setupBuildInfo: PRODUCT  yyyyy, mode=25, isFinal=true
  9536  9536 D Application: onCreate: com.xxx.aaa, 9536, 10131 brand=Google, device=xxx, manufacturer=Google, model=hahahahh, name=yyyyy

3.总结

    这个修改不是对每个APP进程都能达到理想效果,如果进程内使用Build这些信息的地方不是APP进程的生命周期方法内,就会失效。因为APP的范围大于APP进程的范围。

  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值