Search code examples
androidandroid-intentintentfilter

Update APP automatically without user interaction facing issue==> Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED


I want to update the APP automatically when a new version is available without user interaction, suppose a new version is available and it is downloaded to Downloads directory in android.

I followed the following example.

Java Sample: https://stackoverflow.com/a/51705614

Kotlin Sample: https://www.sisik.eu/blog/android/dev-admin/update-app

facing this exception

system_process W/ActivityManager: Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED from pid=-1, uid=10191
system_process W/ActivityManager: Unable to send startActivity intent
    java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED from pid=-1, uid=10191
        at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:21323)
        at com.android.server.am.ActivityManagerService.broadcastIntentInPackage(ActivityManagerService.java:21974)
        at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:372)
        at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:245)
        at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:8446)
        at android.content.IntentSender.sendIntent(IntentSender.java:191)
        at android.content.IntentSender.sendIntent(IntentSender.java:155)
        at com.android.server.pm.PackageInstallerService$PackageInstallObserverAdapter.onUserActionRequired(PackageInstallerService.java:888)
        at android.app.PackageInstallObserver$1.onUserActionRequired(PackageInstallObserver.java:28)
        at com.android.server.pm.PackageInstallerSession.commitLocked(PackageInstallerSession.java:951)
        at com.android.server.pm.PackageInstallerSession.access$200(PackageInstallerSession.java:120)
        at com.android.server.pm.PackageInstallerSession$3.handleMessage(PackageInstallerSession.java:294)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:193)
        at android.os.HandlerThread.run(HandlerThread.java:65)

AndroidManifest.xml

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AutoUpdateAppPractice"
        android:usesCleartextTraffic="true">

        <receiver
            android:name="UpdateReceiver"
            android:enabled="true"
            android:exported="true">

            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REPLACED" />
                <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
            </intent-filter>

        </receiver>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.PACKAGE_ADDED" />
                <action android:name="android.intent.action.INSTALL_PACKAGE" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

CustomPackageInstaller.java

package com.odine.autoupdateapppractice;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class CustomPackageInstaller {

    public static void installPackage(Context context, String installSessionId, String packageName, InputStream apkStream) {

        PackageManager packageManger = context.getPackageManager();
        PackageInstaller packageInstaller = packageManger.getPackageInstaller();

        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);

        params.setAppPackageName(packageName);
        PackageInstaller.Session session = null;

        try {
            Log.e(TAG, "installPackage: try");

            int sessionId = packageInstaller.createSession(params);
            session = packageInstaller.openSession(sessionId);
            OutputStream out = session.openWrite(installSessionId, 0, -1);
            byte buffer[] = new byte[1024];
            int length;
            int count = 0;
            while ((length = apkStream.read(buffer)) != -1) {
                out.write(buffer, 0, length);
                count += length;
            }
            session.fsync(out);
            out.close();

            Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED);
            session.commit(PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT).getIntentSender());


        } catch (Exception ex) {
            Log.e(TAG, "installPackage: catch");
            ex.printStackTrace();

        } finally {
            Log.e(TAG, "installPackage: finally");

            if (session != null) {
                session.close();
            }
        }

    }

}

and inside my MainActivity.java on button click calling CustomPackageInstaller.installPackage() written in above class

 File file= new File(filePath);
 InputStream targetStream = new FileInputStream(file);

 CustomPackageInstaller.installPackage(
                MainActivity.this,
                "2",
                "com.odine.autoupdateapppractice",
                targetStream);

Solution

  • The error message you are getting pretty much tells you what the problem is. You have requested that the package installer notify you on completion by sending a broacast Intent with ACTION = android.intent.action.PACKAGE_ADDED. This broadcast Intent can only be sent by the Android framework. Regular apps cannot send this broadcast Intent.

    You should use an explicit Intent, where you specify the component (package name and class name) for this purpose. You can have the package installer launch an Activity or a BroadcastReceiver for this purpose.


    NOTE: Your app must be device owner to be able to do this without user interaction.