package com.koushikdutta.superuser;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
-
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import com.koushikdutta.superuser.util.Settings;
import com.koushikdutta.superuser.util.StreamUtility;
+import com.koushikdutta.superuser.util.SuHelper;
import com.koushikdutta.widgets.BetterListActivity;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
public class MainActivity extends BetterListActivity {
public MainActivity() {
super(PolicyFragment.class);
return super.onCreateOptionsMenu(menu);
}
+
+ private String getArch() {
+ String prop = System.getProperty("os.arch");
+ if (prop.contains("x86") || prop.contains("i686") || prop.contains("i386")) {
+ return "x86";
+ } else if (prop.contains("mips")) {
+ return "mips";
+ } else {
+ return "armeabi";
+ }
+ }
File extractSu() throws IOException, InterruptedException {
- Process p = Runtime.getRuntime().exec("cat /proc/cpuinfo");
- String contents = StreamUtility.readToEnd(p.getInputStream());
- p.getInputStream().close();
- p.waitFor();
- contents = contents.toLowerCase();
- String arch = "armeabi";
- if (contents.contains("x86"))
- arch = "x86";
ZipFile zf = new ZipFile(getPackageCodePath());
- ZipEntry su = zf.getEntry("assets/" + arch + "/su");
+ ZipEntry su = zf.getEntry("assets/" + getArch() + "/su");
InputStream zin = zf.getInputStream(su);
File ret = getFileStreamPath("su");
FileOutputStream fout = new FileOutputStream(ret);
fout.close();
return ret;
}
-
+
void doRecoveryInstall() {
final ProgressDialog dlg = new ProgressDialog(this);
dlg.setTitle(R.string.installing);
File zip = getFileStreamPath("superuser.zip");
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zip));
doEntry(zout, "assets/update-binary", "META-INF/com/google/android/update-binary");
+ doEntry(zout, "assets/install-recovery.sh", "install-recovery.sh");
zout.close();
+ ZipFile zf = new ZipFile(getPackageCodePath());
+ ZipEntry ze = zf.getEntry("assets/" + getArch() + "/reboot");
+ InputStream in;
+ FileOutputStream reboot;
+ StreamUtility.copyStream(in = zf.getInputStream(ze), reboot = openFileOutput("reboot", MODE_PRIVATE));
+ reboot.close();
+ in.close();
+
final File su = extractSu();
String command =
"chmod 644 /cache/superuser.zip\n" +
"chmod 644 /cache/recovery/command\n" +
"sync\n" +
+ String.format("chmod 755 %s\n", getFileStreamPath("reboot").getAbsolutePath()) +
"reboot recovery\n";
Process p = Runtime.getRuntime().exec("su");
p.getOutputStream().write(command.getBytes());
p.getOutputStream().close();
+ File rebootScript = getFileStreamPath("reboot.sh");
+ StreamUtility.writeFile(rebootScript, "reboot recovery ; " + getFileStreamPath("reboot").getAbsolutePath() + " recovery ;");
+ p.waitFor();
+ Runtime.getRuntime().exec(new String[] { "su", "-c", ". " + rebootScript.getAbsolutePath() });
if (p.waitFor() != 0)
throw new Exception("non zero result");
}
"rm /system/app/SuperUser.*\n" +
"rm /system/app/SuperSU.*\n" +
String.format("cat %s > /system/xbin/su\n", su.getAbsolutePath()) +
- "chmod 6777 /system/xbin/su\n" +
+ "chmod 6755 /system/xbin/su\n" +
"ln -s /system/xbin/su /system/bin/su\n" +
"mount -oro,remount /system\n" +
"sync\n";
p.getOutputStream().close();
if (p.waitFor() != 0)
throw new Exception("non zero result");
- checkSu();
+ SuHelper.checkSu(MainActivity.this);
}
catch (Exception ex) {
_error = true;
- ex.printStackTrace();
+ Log.e("Superuser", "error upgrading", ex);
}
dlg.dismiss();
final boolean error = _error;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.install);
builder.setMessage(R.string.install_superuser_info);
- builder.setPositiveButton(R.string.install, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- doSystemInstall();
- }
- });
+ if (Build.VERSION.SDK_INT < 18) {
+ builder.setPositiveButton(R.string.install, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ doSystemInstall();
+ }
+ });
+ }
builder.setNegativeButton(android.R.string.cancel, null);
builder.setNeutralButton(R.string.recovery_install, new OnClickListener() {
@Override
builder.create().show();
}
- void checkSu() throws Exception {
- Process p = Runtime.getRuntime().exec("su -v");
- String result = Settings.readToEnd(p.getInputStream());
- Log.i("Superuser", "Result: " + result);
- if (0 != p.waitFor())
- throw new Exception("non zero result");
- if (result == null)
- throw new Exception("no data");
- if (!result.contains(getPackageName()))
- throw new Exception("unknown su");
- // TODO: upgrades herp derp
+ private void saveWhatsNew() {
+ Settings.setString(this, "whats_new", WHATS_NEW);
+ }
+
+ // this is intentionally not localized as it will change constantly.
+ private static final String WHATS_NEW = "Added support for Android 4.3.";
+ protected void doWhatsNew() {
+ if (WHATS_NEW.equals(Settings.getString(this, "whats_new")))
+ return;
+ saveWhatsNew();
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.whats_new);
+ builder.setIcon(R.drawable.ic_launcher);
+ builder.setMessage(WHATS_NEW);
+ builder.setPositiveButton(R.string.rate, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent i = new Intent();
+ i.setData(Uri.parse("market://details?id=com.koushikdutta.superuser"));
+ startActivity(i);
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.create().show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
+ Settings.applyDarkThemeSetting(this, R.style.SuperuserDarkActivity);
super.onCreate(savedInstanceState);
+ if (Settings.getBoolean(this, "first_run", true)) {
+ saveWhatsNew();
+ Settings.setBoolean(this, "first_run", false);
+ }
+
final ProgressDialog dlg = new ProgressDialog(this);
dlg.setTitle(R.string.superuser);
dlg.setMessage(getString(R.string.checking_superuser));
dlg.show();
new Thread() {
public void run() {
- boolean error = false;
+ boolean _error = false;
try {
- checkSu();
+ SuHelper.checkSu(MainActivity.this);
}
catch (Exception e) {
e.printStackTrace();
- error = true;
+ _error = true;
}
+ final boolean error = _error;
dlg.dismiss();
- if (error) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (error) {
doInstall();
}
- });
- }
+ else {
+ doWhatsNew();
+ }
+ }
+ });
};
}.start();
}