2 * Copyright (C) 2013 Koushik Dutta (@koush)
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.koushikdutta.superuser;
20 import java.io.FileInputStream;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.zip.ZipEntry;
25 import java.util.zip.ZipFile;
26 import java.util.zip.ZipOutputStream;
28 import android.app.AlertDialog;
29 import android.app.ProgressDialog;
30 import android.content.DialogInterface;
31 import android.content.DialogInterface.OnClickListener;
32 import android.os.Bundle;
33 import android.util.Log;
34 import android.view.Menu;
35 import android.view.MenuItem;
36 import android.view.MenuItem.OnMenuItemClickListener;
38 import com.koushikdutta.superuser.util.Settings;
39 import com.koushikdutta.superuser.util.StreamUtility;
40 import com.koushikdutta.widgets.BetterListActivity;
42 public class MainActivity extends BetterListActivity {
43 public MainActivity() {
44 super(PolicyFragment.class);
47 public PolicyFragmentInternal getFragment() {
48 return (PolicyFragmentInternal)super.getFragment();
52 public boolean onCreateOptionsMenu(Menu menu) {
53 MenuItem about = menu.add(R.string.about);
54 about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
56 public boolean onMenuItemClick(MenuItem item) {
57 getFragment().setContent(new AboutFragment(), true, getString(R.string.about));
62 return super.onCreateOptionsMenu(menu);
65 File extractSu() throws IOException, InterruptedException {
66 Process p = Runtime.getRuntime().exec("cat /proc/cpuinfo");
67 String contents = StreamUtility.readToEnd(p.getInputStream());
68 p.getInputStream().close();
70 contents = contents.toLowerCase();
71 String arch = "armeabi";
72 if (contents.contains("x86"))
74 ZipFile zf = new ZipFile(getPackageCodePath());
75 ZipEntry su = zf.getEntry("assets/" + arch + "/su");
76 InputStream zin = zf.getInputStream(su);
77 File ret = getFileStreamPath("su");
78 FileOutputStream fout = new FileOutputStream(ret);
79 StreamUtility.copyStream(zin, fout);
86 void doRecoveryInstall() {
87 final ProgressDialog dlg = new ProgressDialog(this);
88 dlg.setTitle(R.string.installing);
89 dlg.setMessage(getString(R.string.installing_superuser));
90 dlg.setIndeterminate(true);
93 void doEntry(ZipOutputStream zout, String entryName, String dest) throws IOException {
94 ZipFile zf = new ZipFile(getPackageCodePath());
95 ZipEntry ze = zf.getEntry(entryName);
96 zout.putNextEntry(new ZipEntry(dest));
98 StreamUtility.copyStream(in = zf.getInputStream(ze), zout);
106 File zip = getFileStreamPath("superuser.zip");
107 ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zip));
108 doEntry(zout, "assets/update-binary", "META-INF/com/google/android/update-binary");
111 final File su = extractSu();
114 String.format("cat %s > /cache/superuser.zip\n", zip.getAbsolutePath()) +
115 String.format("cat %s > /cache/su\n", su.getAbsolutePath()) +
116 String.format("cat %s > /cache/Superuser.apk\n", getPackageCodePath()) +
117 "mkdir /cache/recovery\n" +
118 "echo '--update_package=CACHE:superuser.zip' > /cache/recovery/command\n" +
119 "chmod 644 /cache/superuser.zip\n" +
120 "chmod 644 /cache/recovery/command\n" +
123 Process p = Runtime.getRuntime().exec("su");
124 p.getOutputStream().write(command.getBytes());
125 p.getOutputStream().close();
126 if (p.waitFor() != 0)
127 throw new Exception("non zero result");
129 catch (Exception ex) {
130 ex.printStackTrace();
133 runOnUiThread(new Runnable() {
136 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
137 builder.setPositiveButton(android.R.string.ok, null);
138 builder.setTitle(R.string.install);
139 builder.setMessage(R.string.install_error);
140 builder.create().show();
148 void doSystemInstall() {
149 final ProgressDialog dlg = new ProgressDialog(this);
150 dlg.setTitle(R.string.installing);
151 dlg.setMessage(getString(R.string.installing_superuser));
152 dlg.setIndeterminate(true);
156 boolean _error = false;
158 final File su = extractSu();
159 final String command =
160 "mount -orw,remount /system\n" +
161 "rm /system/xbin/su\n" +
162 "rm /system/bin/su\n" +
163 "rm /system/app/Supersu.*\n" +
164 "rm /system/app/superuser.*\n" +
165 "rm /system/app/supersu.*\n" +
166 "rm /system/app/SuperUser.*\n" +
167 "rm /system/app/SuperSU.*\n" +
168 String.format("cat %s > /system/xbin/su\n", su.getAbsolutePath()) +
169 "chmod 6777 /system/xbin/su\n" +
170 "ln -s /system/xbin/su /system/bin/su\n" +
171 "mount -oro,remount /system\n" +
173 Process p = Runtime.getRuntime().exec("su");
174 p.getOutputStream().write(command.getBytes());
175 p.getOutputStream().close();
176 if (p.waitFor() != 0)
177 throw new Exception("non zero result");
180 catch (Exception ex) {
182 ex.printStackTrace();
185 final boolean error = _error;
186 runOnUiThread(new Runnable() {
189 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
190 builder.setPositiveButton(android.R.string.ok, null);
191 builder.setTitle(R.string.install);
194 builder.setMessage(R.string.install_error);
197 builder.setMessage(R.string.install_success);
199 builder.create().show();
207 AlertDialog.Builder builder = new AlertDialog.Builder(this);
208 builder.setTitle(R.string.install);
209 builder.setMessage(R.string.install_superuser_info);
210 builder.setPositiveButton(R.string.install, new OnClickListener() {
212 public void onClick(DialogInterface dialog, int which) {
216 builder.setNegativeButton(android.R.string.cancel, null);
217 builder.setNeutralButton(R.string.recovery_install, new OnClickListener() {
219 public void onClick(DialogInterface dialog, int which) {
223 builder.create().show();
226 void checkSu() throws Exception {
227 Process p = Runtime.getRuntime().exec("su -v");
228 String result = Settings.readToEnd(p.getInputStream());
229 Log.i("Superuser", "Result: " + result);
230 if (0 != p.waitFor())
231 throw new Exception("non zero result");
233 throw new Exception("no data");
234 if (!result.contains(getPackageName()))
235 throw new Exception("unknown su");
236 // TODO: upgrades herp derp
240 protected void onCreate(Bundle savedInstanceState) {
241 super.onCreate(savedInstanceState);
243 final ProgressDialog dlg = new ProgressDialog(this);
244 dlg.setTitle(R.string.superuser);
245 dlg.setMessage(getString(R.string.checking_superuser));
246 dlg.setIndeterminate(true);
250 boolean error = false;
254 catch (Exception e) {
260 runOnUiThread(new Runnable() {