在Android 10上安装更新同一应用程序的apk失败;java.lang.SecurityException:文件仍处于打开状态
我们的应用程序从我们的服务器下载一个APK,并运行它来升级自身。如和中所述,如果移动设备已升级到Android 10,且“未发现任何可处理意图的活动”,则与之前的情况不同 我们已尝试使用PackageInstaller重写此代码,如示例中所示 ,但现在改为获取此错误:在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
信号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());
}
}