Android 静默安装并自动重启,需要获取ROOT 权限

我看网上很多同仁说,用这套代码可以完成静默安装,但不能重启,我也尝试过貌似确实不行。既然设备都ROOT了, 也静默安装了, 写个自启哪有这么难吗? ? ?
我分析是,原作者发的广播非延时的, 或者静默安装还没完成,应用就崩了,广播压根就没有发出去。所以我的思路是,直接抓应用异常,换一种自启思路,多加一个机制。

* * * ROOT版本设备可用, 直接上,干活

1. 添加权限

虽然设备可以获得root权限,理论上能获取所有权限,但如果不加下面权限,运行时会报错,另外 一定要注意 第一个权限 的等级 protectionLevel 也要加一下

    <uses-permission
        android:name="android.permission.INSTALL_PACKAGES"
        android:protectionLevel="signature|privileged" />
    	<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
2. 添加 sharedUserId

AndroidManifest.xml 根节点下添加

    android:sharedUserId="android.uid.packageinstaller"

3. 核心工具类

该代码来自网上一个大神撰写,测试可用

public class SystemCtrlUtil {

    /**
     * root下静默安装
     * */
    public static boolean rootSlienceInstallApk(String apkPath){
        PrintWriter PrintWriter = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec("su");
            PrintWriter = new PrintWriter(process.getOutputStream());
            PrintWriter.println("chmod 777 "+apkPath);
            PrintWriter.println("export LD_LIBRARY_PATH=/vendor/lib:/system/lib");
            PrintWriter.println("pm install -r "+apkPath);
//          PrintWriter.println("exit");
            PrintWriter.flush();
            PrintWriter.close();
            int value = process.waitFor();
            return returnResult(value);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(process!=null){
                process.destroy();
            }
        }
        return false;
    }

    /**
     * root下启动apk
     * */
    public static boolean rootStartApk(String packageName,String activityName){
        boolean isSuccess = false;
        String cmd = "am start -n " + packageName + "/" + activityName + " \n";
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(cmd);
            int value = process.waitFor();
            return returnResult(value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            if(process!=null){
                process.destroy();
            }
        }
        return isSuccess;
    }



    /**
     * root下静默删除
     * */
    public static boolean rootSlienceUninstallApk(String packageName){
        PrintWriter PrintWriter = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec("su");
            PrintWriter = new PrintWriter(process.getOutputStream());
            PrintWriter.println("LD_LIBRARY_PATH=/vendor/lib:/system/lib ");
            PrintWriter.println("pm uninstall "+packageName);
            PrintWriter.flush();
            PrintWriter.close();
            int value = process.waitFor();
            return returnResult(value);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(process!=null){
                process.destroy();
            }
        }
        return false;
    }



    /**
     * 判断手机是否有root权限
     */
    public static boolean sysHasRootPerssion(){
        PrintWriter PrintWriter = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec("su");
            PrintWriter = new PrintWriter(process.getOutputStream());
            PrintWriter.flush();
            PrintWriter.close();
            int value = process.waitFor();
            return returnResult(value);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(process!=null){
                process.destroy();
            }
        }
        return false;
    }

    /**
     * root下执行cmd的返回值
     * */
    private static boolean returnResult(int value){
        // 代表成功
        if (value == 0) {
            return true;
        } else if (value == 1) { // 失败
            return false;
        } else { // 未知情况
            return false;
        }
    }


    /**
     * 判断app是否有root权限
     */
    public static boolean appHasRootPerssion(Context context){
        return RootCommand("chmod 777 "+context.getPackageCodePath());
    }


    /**
     * 应用程序运行命令获取 Root权限,设备必须已破解(获得ROOT权限)
     * @param command 命令:String apkRoot="chmod 777 "+getPackageCodePath(); RootCommand(apkRoot);
     * @return 应用程序是/否获取Root权限
     */
    public static boolean RootCommand(String command)
    {
        Process process = null;
        DataOutputStream os = null;
        try
        {
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes(command + "\n");
            os.writeBytes("exit\n");
            os.flush();
            return returnResult(process.waitFor());
        } catch (Exception e)
        {
            Log.d("*** DEBUG ***", "ROOT REE" + e.getMessage());
            return false;
        } finally
        {
            try
            {
                if (os != null)
                {
                    os.close();
                }
                process.destroy();
            } catch (Exception e)
            {
            }
        }
    }

}

工具类使用


    public static void sinlenceInstallApk(String apkPath, String apkName) {
        Log.i(TAG, "sinlenceInstallApk():-----------------");
        if (!SystemCtrlUtil.sysHasRootPerssion()) {
            Log.e(TAG, "系统尚无Root权限");
            return;
        }
        Log.i(TAG, "系统有Root权限");

        File apkfile = new File(apkPath, apkName);
        if (!apkfile.exists()) {
            Log.e(TAG, "尚无APK文件");
            return;
        }

        //4、静默安装
        if (SystemCtrlUtil.rootSlienceInstallApk(apkPath + "/" + apkName)) {
            Log.i(TAG, "静默安装成功");

            //5、执行此命令后:BootReceiver 监听到Intent.ACTION_PACKAGE_REPLACED,然后自启动
            if (SystemCtrlUtil.rootStartApk("com.winspread.adscreenplayer", "SplashActivity")) {
                Log.i(TAG, "静默安装后启动APP成功");
            } else {
                Log.e(TAG, "静默安装后启动APP失败!!!");
            }

        } else {
            Log.e(TAG, "静默安装失败!!!");
        }
    }

4. 添加系统广播监听,让设备自动重启

public class SystemEventReceiver extends BroadcastReceiver {

    private static final String TAG = ">>>>>>SystemReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction().toString();
        switch (action) {
            case "wits.action.reboot":
                Log.i(TAG, "wits.action.reboot");
                break;
            case "wits.action.shutdown":
                Log.i(TAG, "wits.action.shutdown");
                break;
            case "android.intent.action.BOOT_COMPLETED":
                Log.i(TAG, "android.intent.action.BOOT_COMPLETED");
                break;
            case "RestartSerivcesForSystemEventReceiver":
                Log.i(TAG, "RestartSerivcesForSystemEventReceiver");
                break;
            case "android.intent.action.MEDIA_MOUNTED":
                Log.i(TAG, "android.intent.action.MEDIA_MOUNTE");
                break;
            case "android.intent.action.MEDIA_UNMOUNTEDD":
                Log.i(TAG, "android.intent.action.MEDIA_UNMOUNTEDD");
                break;
            case "android.intent.action.MEDIA_EJECT":
                Log.i(TAG, "android.intent.action.MEDIA_EJECT");
                break;
            case "android.intent.action.SERVICE_STATE":
                Log.i(TAG, "android.intent.action.SERVICE_STATE");
                break;
        }
        if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
            Intent ootStartIntent = new Intent(context, SplashActivity.class);
            ootStartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(ootStartIntent);
        }

        if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {
            Intent localIntent = new Intent(context, SplashActivity.class);
            localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(localIntent);
        }
    }
}

注册广播, 其实我这里注册了N多广播,包括APP 开机自启

        <receiver
            android:name=".SystemEventReceiver"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
            <intent-filter>
                <action android:name="RestartSerivcesForSystemEventReceiver" />
            </intent-filter>
            <intent-filter>
                <action android:name="wits.action.reboot" />
            </intent-filter>
            <intent-filter>
                <action android:name="wits.action.shutdown" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SERVICE_STATE" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_MOUNTED" />
                <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
                <action android:name="android.intent.action.MEDIA_EJECT" />

                <data android:scheme="file" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_ADDED" /> <!-- add -->
                <action android:name="android.intent.action.PACKAGE_REPLACED" /> <!-- update -->
                <action android:name="android.intent.action.PACKAGE_REMOVED" /> <!-- delete -->
                <action android:name="android.intent.action.PACKAGE_RESTARTED" /> <!-- restart -->
                <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- completed -->
                <data android:scheme="package" />
            </intent-filter>
        </receiver>

到这里理论上静默安装,自动重启是可以了

4. 如果不能自动重启,解决办法

我的思路是, 抓软件崩溃,然后自动重启。因为我们可以理解静默安装后,不自动重启,可能是出现了BUG, 导致异常了。

  • 自动重启工具类
public class RestartAPPTool {

    /***重启整个APP*/
    public static void restartAPP(Context context) {
        restartAPP(context, 3000);
    }

    /**
     * 重启整个APP
     *
     * @param context
     * @param Delayed 延迟多少毫秒
     */
    public static void restartAPP(Context context, long Delayed) {

        /**开启一个新的服务,用来重启本APP*/
        Log.i("RestartAPPTool", "27");
        Intent intent = new Intent(context, KillSelfService.class);
        intent.putExtra("PackageName", context.getPackageName());
        intent.putExtra("Delayed", Delayed);
        context.startService(intent);

        /**杀死整个进程**/
        android.os.Process.killProcess(android.os.Process.myPid());
//        System.exit(1);
    }
}
  • 自动重启服务(自杀式)
public class KillSelfService extends Service {
    /**
     * 关闭应用后多久重新启动
     */
    private static long stopDelayed = 3000;
    private String PackageName = "com.winspread.adscreenplayer";
    private Handler handler;

    public KillSelfService() {
        Log.i("KillSelfService", "21");
        handler = new Handler();
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        Log.i("KillSelfService", "26");
        if (intent != null) {
            stopDelayed = intent.getLongExtra("Delayed", 3000);
            PackageName = intent.getStringExtra("PackageName");
        }
        handler.postDelayed(() -> {
            Log.i("KillSelfService", "30");
            Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(PackageName);
            startActivity(LaunchIntent);
            KillSelfService.this.stopSelf();
            Log.i("KillSelfService", "34");
        }, stopDelayed);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

  • 注册服务
 <service android:name=".server.KillSelfService" />
  • 自定义异常处理类
public class CrashHandler implements Thread.UncaughtExceptionHandler {

    /**
     * The constant TAG.
     */
    public static final String TAG = "CrashHandler";

    // CrashHandler 实例
    private static CrashHandler INSTANCE = new CrashHandler();

    // 程序的 Context 对象
    private Context mContext;

    // 系统默认的 UncaughtException 处理类
    private Thread.UncaughtExceptionHandler mDefaultHandler;

    // 用来存储设备信息和异常信息
    private Map<String, String> infos = new HashMap<String, String>();

    // 用于格式化日期,作为日志文件名的一部分
    private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

    /**
     * 保证只有一个 CrashHandler 实例
     */
    private CrashHandler() {
    }

    /**
     * 获取 CrashHandler 实例 ,单例模式
     *
     * @return the instance
     */
    public static CrashHandler getInstance() {
        return INSTANCE;
    }

    /**
     * 初始化
     *
     * @param context the context
     */
    public void init(Context context) {
        mContext = context;

        // 获取系统默认的 UncaughtException 处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

        // 设置该 CrashHandler 为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 当 UncaughtException 发生时会转入该函数来处理
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            // 如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            RestartAPPTool.restartAPP(mContext);
        }
    }

    /**
     * 自定义错误处理,收集错误信息,发送错误报告等操作均在此完成
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回 false
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return false;
        }
        // 使用 Toast 来显示异常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(mContext, "异常退出", Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();
        return true;
    }

}
  • 在 Application 初始化异常处理
        if (!BuildConfig.DEBUG) {
            CrashHandler crashHandler = CrashHandler.getInstance();
            crashHandler.init(this);
        }

你可能感兴趣的:(知识积累,root,静默安装,自动重启)