在Android 10上安装更新同一应用程序的apk失败;java.lang.SecurityException:文件仍处于打开状态

在Android 10上安装更新同一应用程序的apk失败;java.lang.SecurityException:文件仍处于打开状态,java,android,apk,android-install-apk,android-10.0,Java,Android,Apk,Android Install Apk,Android 10.0,我们的应用程序从我们的服务器下载一个APK,并运行它来升级自身。如和中所述,如果移动设备已升级到Android 10,且“未发现任何可处理意图的活动”,则与之前的情况不同 我们已尝试使用PackageInstaller重写此代码,如示例中所示 ,但现在改为获取此错误: 信号6(SIGABRT),代码-1(SIU队列),故障地址-------- 中止消息:“JNI在应用程序中检测到错误:调用JNI GetStaticMethodID时出现挂起异常java.lang.SecurityExceptio

我们的应用程序从我们的服务器下载一个APK,并运行它来升级自身。如和中所述,如果移动设备已升级到Android 10,且“未发现任何可处理意图的活动”,则与之前的情况不同

我们已尝试使用PackageInstaller重写此代码,如示例中所示 ,但现在改为获取此错误:

信号6(SIGABRT),代码-1(SIU队列),故障地址--------
中止消息:“JNI在应用程序中检测到错误:调用JNI GetStaticMethodID时出现挂起异常java.lang.SecurityException:文件仍处于打开状态。”
位于java.lang.Exception android.os.Parcel.createException(int,java.lang.String)(Parcel.java:2071)
在void android.os.Parcel.readException(int,java.lang.String)(Parcel.java:2039)中
位于void android.os.Parcel.readException()(Parcel.java:1987)
在void android.content.pm.IPackageInstallerSession$Stub$Proxy.commit(android.content.IntentSender,布尔值)(IPackageInstallerSession.java:593)
在void android.content.pm.PackageInstaller$Session.commit(android.content.IntentSender)(PackageInstaller.java:1072)中
在void com.mycompany.myApp.QtJavaCustomBridge.JIntentActionInstallApk(java.lang.String)(QtJavaCustomBridge.java:301)上
在void org.qtproject.qt5.android.QtNative.startQtApplication()上(QtNative.java:-2)
位于void org.qtproject.qt5.android.QtNative$7.run()(QtNative.java:374)
位于void org.qtproject.qt5.android.QtThread$1.run()(QtThread.java:61)
位于void java.lang.Thread.run()(Thread.java:919)
原因:android.os.RemoteException:远程堆栈跟踪:
位于com.android.server.pm.PackageInstallerSession.AssertNowriteFileTransfersPenlocked(PackageInstallerSession.java:837)
位于com.android.server.pm.PackageInstallerSession.sealAndValidateLocked(PackageInstallerSession.java:1094)
位于com.android.server.pm.PackageInstallerSession.markAsCommitted(PackageInstallerSession.java:987)
位于com.android.server.pm.PackageInstallerSession.commit(PackageInstallerSession.java:849)
位于android.content.pm.IPackageInstallerSession$Stub.onTransact(IPackageInstallerSession.java:306)
(可丢弃,无堆栈跟踪)
下面是我们使用的代码:

公共静态最终字符串TAG=“JAVA”; public static final String PACKAGE\u INSTALLED\u ACTION=“com.mycompany.myApp.SESSION\u API\u PACKAGE\u INSTALLED”; 公共静态无效JIntentActionInstallApk(最终字符串文件名) { PackageInstaller.Session Session=null; 试一试{ Log.i(标记“JIntentActionInstallApk”+文件名); PackageInstaller PackageInstaller=MyAppActivity.getActivityInstance().getPackageManager().getPackageInstaller(); Log.i(标记“JIntentActionInstallApk-got-packageInstaller”); PackageInstaller.SessionParams params=新PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE(完整安装); Log.i(标记“JIntentActionInstallApk-set SessionParams”); int sessionId=packageInstaller.createSession(参数); session=packageInstaller.openSession(sessionId); Log.i(标记“JIntentActionInstallApk-会话已打开”); //创建安装状态接收器。 上下文上下文=MyAppActivity.getActivityInstance().getApplicationContext(); addApkToInstallSession(上下文、文件名、会话); Log.i(标记“JIntentActionInstallApk-apk添加到会话中”); 意向意向=新意向(上下文,MyAppActivity.class); intent.setAction(MyAppActivity.PACKAGE\u INSTALLED\u ACTION); PendingEvent PendingEvent=PendingEvent.getActivity(上下文,0,意图,0); IntentSender statusReceiver=PendingEvent.getIntentSender(); //提交会话(这将启动安装工作流)。 提交(statusReceiver); Log.i(标签“JIntentActionInstallApk-承诺”); }捕获(IOE异常){ 抛出新的RuntimeException(“无法安装包”,e); }捕获(运行时异常e){ if(会话!=null){ 会话。放弃(); } 投掷e; } } 私有静态void addApkToInstallSession(上下文上下文、字符串文件名、PackageInstaller.Session会话) { Log.i(标记“addApkToInstallSession”+文件名); //建议将文件大小传递给openWrite()。否则安装可能失败 //如果磁盘快满了。 试一试{ OutputStream packageInSession=session.openWrite(“包”,0,-1); 输入流输入; Uri=Uri.parse(文件名); input=context.getContentResolver().openInputStream(uri); 如果(输入!=null){ Log.i(标记“input.available:+input.available()); 字节[]缓冲区=新字节[16384]; int n; 而((n=input.read(buffer))>=0){ packageInSession.write(缓冲区,0,n); } } 否则{ Log.i(标记“addApkToInstallSession failed”); 抛出新IOException(“addApkToInstallSession”); } } 捕获(例外e){ Log.i(标记“addapktoinstallsessionfailed2”+e.toString()); } } ... @凌驾 受保护的void onNewIntent(意图){ Bundle extras=intent.getExtras(); if(安装了包\u\u ACTION.equals(intent.getAction())){ int status=extras.getInt(PackageInstaller.EXTRA_status); String message=extras.getString(PackageInstaller.EXTRA_状态_message); 开关(状态){ 案例包Installer.STATUS\u PENDING\u USER\u操作: //此测试应用程序没有权限,因此用户必须确认安装。 意向确认=(意向)额外获取(意向.额外意向); 星触觉(确认性);
public static void JIntentActionInstallApk(final String filename)
    {
        PackageInstaller.Session session = null;
        try {
            Log.i(TAG, "JIntentActionInstallApk " + filename);

            if(Build.VERSION.SDK_INT < 21) {
                //as PackageInstaller was added in API 21, let's use the old way of doing it prior to 21
                Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
                Uri apkUri = Uri.parse(filename);
                Context context = MyAppActivity.getQtActivityInstance().getApplicationContext();
                ApplicationInfo appInfo = context.getApplicationInfo();
                intent.setData(apkUri);
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
                intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
                intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                     appInfo.packageName);
                MyAppActivity.getQtActivityInstance().startActivity(intent);
            }
            else  {
                // API level 21 or higher, we need to use PackageInstaller
                PackageInstaller packageInstaller = MyAppActivity.getQtActivityInstance().getPackageManager().getPackageInstaller();
                Log.i(TAG, "JIntentActionInstallApk - got packageInstaller");
                PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                Log.i(TAG, "JIntentActionInstallApk - set SessionParams");
                int sessionId = packageInstaller.createSession(params);
                session = packageInstaller.openSession(sessionId);
                Log.i(TAG, "JIntentActionInstallApk - session opened");

                // Create an install status receiver.
                Context context = MyAppActivity.getQtActivityInstance().getApplicationContext();
                addApkToInstallSession(context, filename, session);
                Log.i(TAG, "JIntentActionInstallApk - apk added to session");

                Intent intent = new Intent(context, MyAppActivity.class);
                intent.setAction(MyAppActivity.PACKAGE_INSTALLED_ACTION);
                PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
                IntentSender statusReceiver = pendingIntent.getIntentSender();
                // Commit the session (this will start the installation workflow).
                session.commit(statusReceiver);
                Log.i(TAG, "JIntentActionInstallApk - commited");
            }
        } catch (IOException e) {
            throw new RuntimeException("Couldn't install package", e);
        } catch (RuntimeException e) {
            if (session != null) {
                session.abandon();
            }
            throw e;
        }
    }

    private static void addApkToInstallSession(Context context, String filename, PackageInstaller.Session session)
    {
           Log.i(TAG, "addApkToInstallSession " + filename);
           // It's recommended to pass the file size to openWrite(). Otherwise installation may fail
           // if the disk is almost full.
           try {
                OutputStream packageInSession = session.openWrite("package", 0, -1);
                InputStream input;
                Uri uri = Uri.parse(filename);
                input = context.getContentResolver().openInputStream(uri);

                if(input != null) {
                   Log.i(TAG, "input.available: " + input.available());
                   byte[] buffer = new byte[16384];
                   int n;
                   while ((n = input.read(buffer)) >= 0) {
                       packageInSession.write(buffer, 0, n);
                   }
                }
                else {
                    Log.i(TAG, "addApkToInstallSession failed");
                    throw new IOException ("addApkToInstallSession");
                }
                packageInSession.close();  //need to close this stream
                input.close();             //need to close this stream
           }
           catch (Exception e) {
               Log.i(TAG, "addApkToInstallSession failed2 " + e.toString());
           }
   }