Install apps silently, with granted INSTALL_PACKAGES permission

后端 未结 16 2228
梦谈多话
梦谈多话 2020-11-22 10:32

I am trying to silently install apk into the system. My app is located in /system/app and successfully granted permission \"android.permission.INSTALL_PACKAGES\"

Ho

相关标签:
16条回答
  • 2020-11-22 10:56

    I have checked how ADB installs apps.
    - It copies the APK to /data/local/tmp
    - it runs 'shell:pm install /data/local/tmp/app.apk'

    I have tried to replicate this behaviour by doing: (on pc, using usb-cable)
    adb push app.apk /sdcard/app.apk
    adb shell
    $ pm install /sdcard/app.apk
    This works. The app is installed.

    I made an application (named AppInstall) which should install the other app.
    (installed normally, non-rooted device)
    It does:
    Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
    But this gives the error:
    java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
    It seems like the error is thrown by pm, not by AppInstall.
    Because the SecurityException is not catched by AppInstall and the app does not crash.

    I've tried the same thing on a rooted device (same app and AppInstall) and it worked like a charm.
    (Also normally installed, not in /system or anything)
    AppInstall didn't even ask root-permission.
    But thats because the shell is always # instead of $ on that device.

    Btw, you need root to install an app in /system, correct?
    I tried adb remount on the non-rooted device and got:
    remount failed: Operation not permitted.
    That's why I could not try the /system thing on the non-rooted device.

    Conclusion: you should use a rooted device
    Hope this helps :)

    0 讨论(0)
  • 2020-11-22 10:56

    Prerequisite:

    Your APK needs to be signed by system as correctly pointed out earlier. One way to achieve that is building the AOSP image yourself and adding the source code into the build.

    Code:

    Once installed as a system app, you can use the package manager methods to install and uninstall an APK as following:

    Install:

    public boolean install(final String apkPath, final Context context) {
        Log.d(TAG, "Installing apk at " + apkPath);
        try {
            final Uri apkUri = Uri.fromFile(new File(apkPath));
            final String installerPackageName = "MyInstaller";
            context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    

    Uninstall:

    public boolean uninstall(final String packageName, final Context context) {
        Log.d(TAG, "Uninstalling package " + packageName);
        try {
            context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    

    To have a callback once your APK is installed/uninstalled you can use this:

    /**
     * Callback after a package was installed be it success or failure.
     */
    private class InstallObserver implements IPackageInstallObserver {
    
        @Override
        public void packageInstalled(String packageName, int returnCode) throws RemoteException {
    
            if (packageName != null) {
                Log.d(TAG, "Successfully installed package " + packageName);
                callback.onAppInstalled(true, packageName);
            } else {
                Log.e(TAG, "Failed to install package.");
                callback.onAppInstalled(false, null);
            }
        }
    
        @Override
        public IBinder asBinder() {
            return null;
        }
    }
    
    /**
     * Callback after a package was deleted be it success or failure.
     */
    private class DeleteObserver implements IPackageDeleteObserver {
    
        @Override
        public void packageDeleted(String packageName, int returnCode) throws RemoteException {
            if (packageName != null) {
                Log.d(TAG, "Successfully uninstalled package " + packageName);
                callback.onAppUninstalled(true, packageName);
            } else {
                Log.e(TAG, "Failed to uninstall package.");
                callback.onAppUninstalled(false, null);
            }
        }
    
        @Override
        public IBinder asBinder() {
            return null;
        }
    }
    
    /**
     * Callback to give the flow back to the calling class.
     */
    public interface InstallerCallback {
        void onAppInstalled(final boolean success, final String packageName);
        void onAppUninstalled(final boolean success, final String packageName);
    }
    

    ===> Tested on Android 8.1 and worked well.

    0 讨论(0)
  • 2020-11-22 10:56

    An 3rd party application cannot install an Android App sliently. However, a 3rd party application can ask the Android OS to install a application.

    So you should define this:

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive");
    startActivity(intent);
    

    You can also try to install it as a system app to grant the permission and ignore this define. (Root Required)

    You can run the following command on your 3rd party app to install an app on the rooted device.

    The code is:

    private void installApk(String filename) {
    File file = new File(filename); 
    if(file.exists()){
        try {   
            final String command = "pm install -r " + file.getAbsolutePath();
            Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
            proc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
     }
    }
    

    I hope that this answer is helpful for you.

    0 讨论(0)
  • 2020-11-22 10:58

    You should define

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

    in your manifest, then if whether you are in system partition (/system/app) or you have your application signed by the manufacturer, you are going to have INSTALL_PACKAGES permission.

    My suggestion is to create a little android project with 1.5 compatibility level used to call installPackages via reflection and to export a jar with methods to install packages and to call the real methods. Then, by importing the jar in your project you will be ready to install packages.

    0 讨论(0)
  • 2020-11-22 10:58

    you can use this in terminal or shell

    adb shell install -g MyApp.apk
    

    see more in develope google

    0 讨论(0)
  • 2020-11-22 11:02

    Try this LD_LIBRARY_PATH=/vendor/lib:/system/lib before pm install. It works well.

    0 讨论(0)
提交回复
热议问题