androidin-app-update

Error when self updating an android application


I have downloaded the apk file that I need successfully. To try if the apk file that I have downloaded is not corrupted and can be installed correctly, I manually click the complete downloaded apk file to update my application and it installs right. Going further, I am trying to install the update automatically. Meaning, as soon as the file is downloaded completely, I want the application to update itself. The application that downloads the file is the same application that will be updated by the updated apk. This should work like the Google In-App update but without the Google Play Store. With the application that downloaded the file is running and by manually tapping the downloaded file, I can still install the update to this application without issues. It's just that, when I try to do this automatically, it gives the error like so:

FATAL EXCEPTION: AsyncTask #1
Process: com.google.android.packageinstaller, PID: 15764
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:325)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: java.lang.SecurityException: Permission Denial: opening provider androidx.core.content.FileProvider from ProcessRecord{f4c3105 15764:com.google.android.packageinstaller/u0a18} (pid=15764, uid=10018) that is not exported from uid 10099
at android.os.Parcel.readException(Parcel.java:1684)
at android.os.Parcel.readException(Parcel.java:1637)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4199)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:5508)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2239)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1520)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1133)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:986)
at android.content.ContentResolver.openInputStream(ContentResolver.java:706)
at com.android.packageinstaller.PackageInstallerActivity$StagingAsyncTask.doInBackground(PackageInstallerActivity.java:792)
at com.android.packageinstaller.PackageInstallerActivity$StagingAsyncTask.doInBackground(PackageInstallerActivity.java:783)
at android.os.AsyncTask$2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
at java.lang.Thread.run(Thread.java:761) 

This is how I implement the opening and attempt to install the update

private void openDownloadedAttachment(final Context context, final long downloadId, Uri uri) {
    DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(downloadId);
    Cursor cursor = downloadManager.query(query);
    if (cursor.moveToFirst()) {
        @SuppressLint("Range")
        int downloadStatus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
        @SuppressLint("Range")
        String downloadLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
        @SuppressLint("Range")
        String downloadMimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
        if ((downloadStatus == DownloadManager.STATUS_SUCCESSFUL) && downloadLocalUri != null) {
            try {
                downloadLocalUri = "/storage/emulated/0/AATv2.apk";
                openDownloadedAttachment(context, Uri.parse(downloadLocalUri), downloadMimeType);
                Intent promptInstall = new Intent(Intent.ACTION_VIEW);
                promptInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                promptInstall.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                promptInstall.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION );
                File file = new File(downloadLocalUri);
                uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName()+".provider",
                        file);
                promptInstall.setDataAndType(uri,
                        "application/vnd.android.package-archive");
                promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(promptInstall);
            }
            catch (ActivityNotFoundException e) {
                e.printStackTrace();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    cursor.close();
}

AndroidManifest

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.INSTALL_PACKAGES"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.DELETE_PACKAGES"
    tools:ignore="ProtectedPermissions" />

<application>
        .....
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>
</application>

provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Solution

  • This is your problem:

        Intent promptInstall = new Intent(Intent.ACTION_VIEW);
        promptInstall.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        promptInstall.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        promptInstall.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION );
    

    You need to call addFlags() instead of setFlags(). When you call addFlags() this adds the flags you specify to the flags that are already set in the Intent. When you call setFlags() this overwrites the flags that are already set in the Intent with the flags you specify.

    In your code, the last call to setFlags() sets FLAG_GRANT_PERSISTABLE_URI_PERMISSION but the other flags (FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION) are cleared.