当前位置: 首页 > article >正文

Android14 原生PackageInstaller安装某些apk报错问题

 最近遇到Android14安装客户一个大型app的时候,执行到开始安装的时候就直接闪退了,查看log发现下面报错:

03-25 18:01:29.531 3085 3085 E AndroidRuntime: java.lang.RuntimeException: Could not copy bitmap to parcel blob. 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.graphics.Bitmap.nativeWriteToParcel(Native Method) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.graphics.Bitmap.writeToParcel(Bitmap.java:2271) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeParcelable(Parcel.java:2606) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageUtil$AppSnippet.writeToParcel(PackageUtil.java:151) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeParcelable(Parcel.java:2606) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeValue(Parcel.java:2507) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeValue(Parcel.java:2384) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeArrayMapInternal(Parcel.java:1320) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Bundle.writeToParcel(Bundle.java:1389) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeBundle(Parcel.java:1389) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.content.Intent.writeToParcel(Intent.java:11826) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeTypedObject(Parcel.java:2225) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2077) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1873) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivityForResult(Activity.java:5634) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivityForResult(Activity.java:5592) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivity(Activity.java:6090) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivity(Activity.java:6057) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity.startInstall(PackageInstallerActivity.java:70 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity.lambda$bindUi$0(PackageInstallerActivity.java 79) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity.$r8$lambda$RCIm8wl1VPqdfQgkgmrBIDbuvOQ(Packag nstallerActivity.java:0) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity$$ExternalSyntheticLambda0.onClick(R8$$Synthet Class:0) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.AlertController$ButtonHandler.handleMessage(AlertController.java:144) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:205) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Looper.loop(Looper.java:294) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8248) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 需要如何修改函数避免错误。

根据上面报错定位到frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageUtil.java 中的writeToParcel函数。
 

public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeString(label.toString());
            Bitmap bmp = getBitmapFromDrawable(icon);
            dest.writeParcelable(bmp, 0);
        }

这个函数是将bmp文件转为parcel blob报错。可能原因是Bitmap 过大。解决办法如下:
 

解决方案:

方案 1:压缩 Bitmap 再传递

由于 writeParcelable 可能不适用于大 Bitmap,可以用 ByteArrayOutputStream 压缩 Bitmapbyte[],然后传输:

public void writeToParcel(@NonNull Parcel dest, int flags) {
    dest.writeString(label.toString());

    Bitmap bmp = getBitmapFromDrawable(icon);
    if (bmp != null) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byte[] byteArray = stream.toByteArray();
        dest.writeByteArray(byteArray);
        System.out.println("Compressed Bitmap size: " + byteArray.length + " bytes");
    } else {
        dest.writeByteArray(null);
    }
}

readFromParcel 时,需要用 BitmapFactory.decodeByteArray() 还原 Bitmap

byte[] byteArray = source.readByteArray();
Bitmap bmp = (byteArray != null) ? BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length) : null;

方案 2:限制 Bitmap 大小

如果你仍然要用 writeParcelable 传输 Bitmap,可以先缩小 Bitmap,比如:

public Bitmap getResizedBitmap(Bitmap bmp, int maxSize) {
    int width = bmp.getWidth();
    int height = bmp.getHeight();
    float scale = Math.min((float) maxSize / width, (float) maxSize / height);
    
    int newWidth = Math.round(scale * width);
    int newHeight = Math.round(scale * height);
    
    return Bitmap.createScaledBitmap(bmp, newWidth, newHeight, true);
}

然后在 writeToParcel 里:

Bitmap bmp = getBitmapFromDrawable(icon);
if (bmp != null) {
    Bitmap resizedBmp = getResizedBitmap(bmp, 200);  // 200px 限制大小
    dest.writeParcelable(resizedBmp, flags);
}

方案 3:避免 Bitmap 传输,使用资源 ID

如果 Bitmap 是来自 Drawable资源文件,最好传递资源 ID,而不是 Bitmap 本身:

 
dest.writeInt(iconResId);

然后在 readFromParcel 里:

int iconResId = source.readInt();
Drawable icon = context.getResources().getDrawable(iconResId, null);

总结:

  • 推荐方案 1:压缩 Bitmap 并使用 writeByteArray() 传输。

  • 如果必须用 writeParcelable:限制 Bitmap 大小(方案 2)。

  • 如果 Bitmap 来源于资源:传递资源 ID 而不是 Bitmap(方案 3)。


http://www.kler.cn/a/610850.html

相关文章:

  • Qt的文件操作
  • MySQL无法链接
  • Oracle 数据库通过exp/imp工具迁移指定数据表
  • WordPress 代码高亮插件 io code highlight
  • 推荐一款好看的 vue3 后台模板
  • 【Unity3D实现UI轮播效果】
  • Spring Boot 自定义 Starter 组件的技术指南
  • 通过按键控制stm32最小系统板上LED的亮灭状态
  • 全文 - MLIR Toy Tutorial Chapter 1: Toy Language and AST
  • CAT1模块 EC800M HTTP 使用后续记录
  • PSA方法计算器(PSA Method Calculator): 鼠标完美灵敏度测试网站
  • 【计算机网络】计算机网络协议、接口与服务全面解析——结合生活化案例与图文详解
  • Jmeter:常用线程组设置策略
  • Axure RP9.0 教程:左侧菜单列表导航 ( 点击父级菜单,子菜单自动收缩或展开)【响应式的菜单导航】
  • 基于人工智能的扫阅卷和数据分析服务需求文档
  • 基于Spring Boot的网上购物商城系统的设计与实现(LW+源码+讲解)
  • 一. 相机模组摆放原理
  • redux ,react-redux,redux-toolkit 简单总结
  • 前端使用WPS WebOffice 做在线文档预览与编辑
  • uniapp主题切换功能,适配H5、小程序