OSDN Git Service

Merge branch 'master' of git://github.com/koush/Superuser
[android-x86/external-koush-Superuser.git] / Superuser / src / com / koushikdutta / superuser / MainActivity.java
1 /*
2  * Copyright (C) 2013 Koushik Dutta (@koush)
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.koushikdutta.superuser;
18
19 import java.io.File;
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;
27
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;
37
38 import com.koushikdutta.superuser.util.Settings;
39 import com.koushikdutta.superuser.util.StreamUtility;
40 import com.koushikdutta.widgets.BetterListActivity;
41
42 public class MainActivity extends BetterListActivity {
43     public MainActivity() {
44         super(PolicyFragment.class);
45     }
46
47     public PolicyFragmentInternal getFragment() {
48         return (PolicyFragmentInternal)super.getFragment();
49     }
50     
51     @Override
52     public boolean onCreateOptionsMenu(Menu menu) {
53         MenuItem about = menu.add(R.string.about);
54         about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
55             @Override
56             public boolean onMenuItemClick(MenuItem item) {
57                 getFragment().setContent(new AboutFragment(), true, getString(R.string.about));
58                 return true;
59             }
60         });
61         
62         return super.onCreateOptionsMenu(menu);
63     }
64     
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();
69         p.waitFor();
70         contents = contents.toLowerCase();
71         String arch = "armeabi";
72         if (contents.contains("x86"))
73             arch = "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);
80         zin.close();
81         zf.close();
82         fout.close();
83         return ret;
84     }
85     
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);
91         dlg.show();
92         new Thread() {
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));
97                 InputStream in;
98                 StreamUtility.copyStream(in = zf.getInputStream(ze), zout);
99                 zout.closeEntry();
100                 in.close();
101                 zf.close();
102             }
103             
104             public void run() {
105                 try {
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");
109                     zout.close();
110
111                     final File su = extractSu();
112
113                     String command =
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" +
121                             "sync\n" +
122                             "reboot recovery\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");
128                 }
129                 catch (Exception ex) {
130                     ex.printStackTrace();
131                     dlg.dismiss();
132
133                     runOnUiThread(new Runnable() {
134                         @Override
135                         public void run() {
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();
141                         }
142                     });
143                 }
144             }
145         }.start();
146     }
147     
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);
153         dlg.show();
154         new Thread() {
155             public void run() {
156                 boolean _error = false;
157                 try {
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" +
172                             "sync\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");
178                     checkSu();
179                 }
180                 catch (Exception ex) {
181                     _error = true;
182                     ex.printStackTrace();
183                 }
184                 dlg.dismiss();
185                 final boolean error = _error;
186                 runOnUiThread(new Runnable() {
187                     @Override
188                     public void run() {
189                         AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
190                         builder.setPositiveButton(android.R.string.ok, null);
191                         builder.setTitle(R.string.install);
192                         
193                         if (error) {
194                             builder.setMessage(R.string.install_error);
195                         }
196                         else {
197                             builder.setMessage(R.string.install_success);
198                         }
199                         builder.create().show();
200                     }
201                 });
202             };
203         }.start();
204     }
205     
206     void doInstall() {
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() {
211             @Override
212             public void onClick(DialogInterface dialog, int which) {
213                 doSystemInstall();
214             }
215         });
216         builder.setNegativeButton(android.R.string.cancel, null);
217         builder.setNeutralButton(R.string.recovery_install, new OnClickListener() {
218             @Override
219             public void onClick(DialogInterface dialog, int which) {
220                 doRecoveryInstall();
221             }
222         });
223         builder.create().show();
224     }
225     
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");
232         if (result == null)
233             throw new Exception("no data");
234         if (!result.contains(getPackageName()))
235             throw new Exception("unknown su");
236         // TODO: upgrades herp derp
237     }
238
239     @Override
240     protected void onCreate(Bundle savedInstanceState) {
241         super.onCreate(savedInstanceState);
242         
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);
247         dlg.show();
248         new Thread() {
249             public void run() {
250                 boolean error = false;
251                 try {
252                     checkSu();
253                 }
254                 catch (Exception e) {
255                     e.printStackTrace();
256                     error = true;
257                 }
258                 dlg.dismiss();
259                 if (error) {
260                     runOnUiThread(new Runnable() {
261                         @Override
262                         public void run() {
263                             doInstall();
264                         }
265                     });
266                 }
267             };
268         }.start();
269     }
270 }