SecurityException:打开未从uid导出的提供程序

时间:2017-11-17 12:04:48

标签: android securityexception android-fileprovider android-securityexception

我有一个不在Play商店的应用程序。我之前能够通过以下代码启动应用程序安装程序:

活动:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/app_path/app_name.apk")), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);

现在,我已将targetSdkVersion更改为25,并对我的代码进行了一些更改,但我收到以下错误:

  

致命异常:AsyncTask#1       进程:com.android.packageinstaller,PID:6499       java.lang.RuntimeException:执行doInBackground()时发生错误       在android.os.AsyncTask $ 3.done(AsyncTask.java:326)       在java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)       at java.util.concurrent.FutureTask.setException(FutureTask.java:223)       在java.util.concurrent.FutureTask.run(FutureTask.java:242)       在android.os.AsyncTask $ SerialExecutor $ 1.run(AsyncTask.java:244)       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)       at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:607)       在java.lang.Thread.run(Thread.java:761)        引起:java.lang.SecurityException:权限拒绝:从ProcessRecord打开提供者in.namespace.appname.comp.GenericFileProvider {ba35e80 6499:com.android.packageinstaller / u0a17}(pid = 6499,uid = 10017),不导出来自uid 10076       在android.os.Parcel.readException(Parcel.java:1684)       在android.os.Parcel.readException(Parcel.java:1637)       在android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4213)       在android.app.ActivityThread.acquireProvider(ActivityThread.java:5535)       在android.app.ContextImpl $ ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2239)       在android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1517)       在android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1131)       在android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:984)       在android.content.ContentResolver.openInputStream(ContentResolver.java:704)       at com.android.packageinstaller.PackageInstallerActivity $ StagingAsyncTask.doInBackground(PackageInstallerActivity.java:804)       在com.android.packageinstaller.PackageInstallerActivity $ StagingAsyncTask.doInBackground(PackageInstallerActivity.java:795)       在android.os.AsyncTask $ 2.call(AsyncTask.java:306)       在java.util.concurrent.FutureTask.run(FutureTask.java:237)       在android.os.AsyncTask $ SerialExecutor $ 1.run(AsyncTask.java:244)       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)       at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:607)       在java.lang.Thread.run(Thread.java:761)

以下是我在代码中所做的更改:

清单中的

<permission
    android:name="in.namespace.appname.fp.READ"
    android:description="@string/file_provider_permission_description"
    android:label="in.namespace.appname.READ_FILE"/>

<uses-permission android:name="in.namespace.appname.fp.READ"/>

<application
    ...
    ...
    <provider
        android:name=".comp.GenericFileProvider"
        android:authorities="in.namespace.appname.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true"
        android:readPermission="in.namespace.appname.fp.READ">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
    .
    .
</application>

在目录GenericFileProvider中创建一个空类comp

public class GenericFileProvider extends FileProvider { }

将活动代码更改为:

File updatedApk = new File(Environment.getExternalStorageDirectory() + "/file_path/appname.apk");
Uri updatedApkUri =  GenericFileProvider.getUriForFile(
     AppUpdateActivity.this,
     "in.namespace.appname.fileprovider",
     updatedApk);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(updatedApkUri, "application/vnd.android.package-archive");

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);

导致此错误的原因是什么?如何解决?

编辑#1

更改了我的清单:

<provider
        android:name=".comp.GenericFileProvider"
        android:authorities="in.namespace.appname.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>

3 个答案:

答案 0 :(得分:1)

就我而言,启动Intent时带有此标志Intent.FLAG_ACTIVITY_NEW_TASK,并且正在引起问题。因此, 我从意图中删除了该标记 ,它开始起作用。

有效示例代码

String myPackageName = getApplicationContext().getPackageName();
File f = new File(Environment.getExternalStorageDirectory() + "/Download/" + downloadName);
Uri mediaUri = FileProvider.getUriForFile(getApplicationContext(), myPackageName + ".provider", f);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(mediaUri, "application/vnd.android.package-archive");
startActivity(intent);

答案 1 :(得分:0)

删除android:readPermission="in.namespace.appname.fp.READ"

答案 2 :(得分:0)

 Uri updatedApkUri =  GenericFileProvider.getUriForFile(
 AppUpdateActivity.this,
 "in.namespace.appname.fileprovider",
 updatedApk);

请将您的代码更改为

 Uri updatedApkUri =  GenericFileProvider.getUriForFile(
 AppUpdateActivity.this,
 BuildConfig.APPLICATION_ID + ".provider",
 updatedApk);

并管理此类权限

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                } else if (Build.VERSION.SDK_INT >= 
Build.VERSION_CODES.JELLY_BEAN) {
                    val clip = ClipData.newUri(contentResolver, "A photo", 
mImageCaptureUri)
                    intent.clipData = clip
                    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                } else {
                    val resInfoList = 
 packageManager.queryIntentActivities(intent, 
 PackageManager.MATCH_DEFAULT_ONLY)
                    for (resolveInfo in resInfoList) {
                        val packageName = 
 resolveInfo.activityInfo.packageName
                        grantUriPermission(packageName, mImageCaptureUri, 
 Intent.FLAG_GRANT_WRITE_URI_PERMISSION or 
 Intent.FLAG_GRANT_READ_URI_PERMISSION)
                    }
                }
            }
            intent.putExtra("return-data", true)