Search code examples
androidsu

clearing multiple apps' data android


I'm able to clear a single package name's data through this snippet. However, i want it to handle more than one package names. in other words, it should clear two more package names' data

    private void clearData() {
        //"com.uc.browser.en"
        //"pm clear com.sec.android.app.sbrowser"
        String cmd = "pm clear com.sec.android.app.sbrowser" ;
        ProcessBuilder pb = new ProcessBuilder().redirectErrorStream(true)
                .command("su");
        Process p = null;
        try {
            p = pb.start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // We must handle the result stream in another Thread first
        StreamReader stdoutReader = new StreamReader(p.getInputStream(),
                CHARSET_NAME);
        stdoutReader.start();

        out = p.getOutputStream();
        try {
            out.write((cmd + "\n").getBytes(CHARSET_NAME));
        } catch (UnsupportedEncodingException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            out.write(("exit" + "\n").getBytes(CHARSET_NAME));
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            out.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            p.waitFor();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String result = stdoutReader.getResult();
    }
}

Solution

  • The ProcessCommandsSU class starts an su process in which to run a list of commands, and provides an interface to deliver the output to an Activity asynchronously. Unlike the example you're following, this class will not block the UI thread. The Activity must implement the OnCommandsReturnListener interface.

    public class ProcessCommandsSU extends Thread {
        public interface OnCommandsReturnListener {
            public void onCommandsReturn(String output);
        }
    
        private final Activity activity;
        private final String[] cmds;
    
        public ProcessCommandsSU(Activity activity, String[] cmds) {
            if(!(activity instanceof OnCommandsReturnListener)) {
                throw new IllegalArgumentException(
                    "Activity must implement OnCommandsReturnListener interface");
            }
    
            this.activity = activity;
            this.cmds = cmds;
        }
    
        public void run() {
            try {
                final Process process = new ProcessBuilder()
                                            .redirectErrorStream(true)
                                            .command("su")
                                            .start();
                final OutputStream os = process.getOutputStream();
                final CountDownLatch latch = new CountDownLatch(1);
                final OutputReader or = new OutputReader(process.getInputStream(), latch);
    
                or.start();
    
                for (int i = 0; i < cmds.length; i++) {
                    os.write((cmds[i] + "\n").getBytes());
                }
    
                os.write(("exit\n").getBytes());
                os.flush();
    
                process.waitFor();
                latch.await();
                process.destroy();
    
                final String output = or.getOutput();
                activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            ((OnCommandsReturnListener) activity).onCommandsReturn(output);
                        }
                    }
                );
            }
            catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        private class OutputReader extends Thread {
            private final InputStream is;
            private final StringBuilder sb = new StringBuilder();
            private final CountDownLatch latch;
    
            public OutputReader(InputStream is, CountDownLatch latch) {
                this.is = is;
                this.latch = latch;
            }
    
            public String getOutput() {
                return sb.toString();
            } 
    
            public void run() {
                try {
                    final BufferedReader reader = new BufferedReader(
                        new InputStreamReader(is));
    
                    String line = "";
                    while ((line = reader.readLine()) != null) {                    
                        sb.append(line + "\n");                     
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
                latch.countDown();
            }
        }
    }
    

    Using the class is quite simple. We first ensure that our Activity implements the interface. We then create an instance, passing the Activity and our array of commands in the constructor, and call its start() method. In the following example, it's assumed that the Activity has a TextView named textOutput to display the returned output:

    public class MainActivity extends Activity
        implements ProcessCommandsSU.OnCommandsReturnListener {
        ...
    
        @Override
        public void onCommandsReturn(String output) {
            textOutput.append(output + "\n");
        }
    
        private void runCommands() {
            final String[] cmds = {
                "ping -c 5 www.google.com",
                "pm list packages android",
                "chdir " + Environment.getExternalStorageDirectory(),
                "ls"
            };
    
            new ProcessCommandsSU(MainActivity.this, cmds).start();
        }
    }
    

    My device is not rooted, so this was tested with the commands you see in the code above. Simply replace those commands with your pm clear commands.