OSDN Git Service

7e4978ce251073638d55253d81c55cf7b20d652d
[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.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.zip.ZipEntry;
24 import java.util.zip.ZipFile;
25 import java.util.zip.ZipOutputStream;
26
27 import android.app.AlertDialog;
28 import android.app.ProgressDialog;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.DialogInterface.OnClickListener;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.view.Menu;
35 import android.view.MenuInflater;
36 import android.view.MenuItem;
37 import android.view.MenuItem.OnMenuItemClickListener;
38
39 import com.koushikdutta.superuser.util.Settings;
40 import com.koushikdutta.superuser.util.StreamUtility;
41 import com.koushikdutta.superuser.util.SuHelper;
42 import com.koushikdutta.widgets.BetterListActivity;
43
44 public class MainActivity extends BetterListActivity {
45     public MainActivity() {
46         super(PolicyFragment.class);
47     }
48
49     public PolicyFragmentInternal getFragment() {
50         return (PolicyFragmentInternal)super.getFragment();
51     }
52     
53     @Override
54     public boolean onCreateOptionsMenu(Menu menu) {
55         MenuInflater mi = new MenuInflater(this);
56         mi.inflate(R.menu.app, menu);
57         MenuItem about = menu.findItem(R.id.about);
58         about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
59             @Override
60             public boolean onMenuItemClick(MenuItem item) {
61                 getFragment().setContent(new AboutFragment(), true, getString(R.string.about));
62                 return true;
63             }
64         });
65         
66         return super.onCreateOptionsMenu(menu);
67     }
68     
69     File extractSu() throws IOException, InterruptedException {
70         Process p = Runtime.getRuntime().exec("cat /proc/cpuinfo");
71         String contents = StreamUtility.readToEnd(p.getInputStream());
72         p.getInputStream().close();
73         p.waitFor();
74         contents = contents.toLowerCase();
75         String arch = "armeabi";
76         if (contents.contains("x86"))
77             arch = "x86";
78         ZipFile zf = new ZipFile(getPackageCodePath());
79         ZipEntry su = zf.getEntry("assets/" + arch + "/su");
80         InputStream zin = zf.getInputStream(su);
81         File ret = getFileStreamPath("su");
82         FileOutputStream fout = new FileOutputStream(ret);
83         StreamUtility.copyStream(zin, fout);
84         zin.close();
85         zf.close();
86         fout.close();
87         return ret;
88     }
89     
90     void doRecoveryInstall() {
91         final ProgressDialog dlg = new ProgressDialog(this);
92         dlg.setTitle(R.string.installing);
93         dlg.setMessage(getString(R.string.installing_superuser));
94         dlg.setIndeterminate(true);
95         dlg.show();
96         new Thread() {
97             void doEntry(ZipOutputStream zout, String entryName, String dest) throws IOException {
98                 ZipFile zf = new ZipFile(getPackageCodePath());
99                 ZipEntry ze = zf.getEntry(entryName);
100                 zout.putNextEntry(new ZipEntry(dest));
101                 InputStream in;
102                 StreamUtility.copyStream(in = zf.getInputStream(ze), zout);
103                 zout.closeEntry();
104                 in.close();
105                 zf.close();
106             }
107             
108             public void run() {
109                 try {
110                     File zip = getFileStreamPath("superuser.zip");
111                     ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zip));
112                     doEntry(zout, "assets/update-binary", "META-INF/com/google/android/update-binary");
113                     zout.close();
114
115                     final File su = extractSu();
116
117                     String command =
118                             String.format("cat %s > /cache/superuser.zip\n", zip.getAbsolutePath()) +
119                             String.format("cat %s > /cache/su\n", su.getAbsolutePath()) +
120                             String.format("cat %s > /cache/Superuser.apk\n", getPackageCodePath()) +
121                             "mkdir /cache/recovery\n" +
122                             "echo '--update_package=CACHE:superuser.zip' > /cache/recovery/command\n" +
123                             "chmod 644 /cache/superuser.zip\n" +
124                             "chmod 644 /cache/recovery/command\n" +
125                             "sync\n" +
126                             "reboot recovery\n";
127                     Process p = Runtime.getRuntime().exec("su");
128                     p.getOutputStream().write(command.getBytes());
129                     p.getOutputStream().close();
130                     if (p.waitFor() != 0)
131                         throw new Exception("non zero result");
132                 }
133                 catch (Exception ex) {
134                     ex.printStackTrace();
135                     dlg.dismiss();
136
137                     runOnUiThread(new Runnable() {
138                         @Override
139                         public void run() {
140                             AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
141                             builder.setPositiveButton(android.R.string.ok, null);
142                             builder.setTitle(R.string.install);
143                             builder.setMessage(R.string.install_error);
144                             builder.create().show();
145                         }
146                     });
147                 }
148             }
149         }.start();
150     }
151     
152     void doSystemInstall() {
153         final ProgressDialog dlg = new ProgressDialog(this);
154         dlg.setTitle(R.string.installing);
155         dlg.setMessage(getString(R.string.installing_superuser));
156         dlg.setIndeterminate(true);
157         dlg.show();
158         new Thread() {
159             public void run() {
160                 boolean _error = false;
161                 try {
162                     final File su = extractSu();
163                     final String command =
164                             "mount -orw,remount /system\n" +
165                             "rm /system/xbin/su\n" +
166                             "rm /system/bin/su\n" +
167                             "rm /system/app/Supersu.*\n" +
168                             "rm /system/app/superuser.*\n" +
169                             "rm /system/app/supersu.*\n" +
170                             "rm /system/app/SuperUser.*\n" +
171                             "rm /system/app/SuperSU.*\n" +
172                             String.format("cat %s > /system/xbin/su\n", su.getAbsolutePath()) +
173                             "chmod 6755 /system/xbin/su\n" +
174                             "ln -s /system/xbin/su /system/bin/su\n" +
175                             "mount -oro,remount /system\n" +
176                             "sync\n";
177                     Process p = Runtime.getRuntime().exec("su");
178                     p.getOutputStream().write(command.getBytes());
179                     p.getOutputStream().close();
180                     if (p.waitFor() != 0)
181                         throw new Exception("non zero result");
182                     SuHelper.checkSu(MainActivity.this);
183                 }
184                 catch (Exception ex) {
185                     _error = true;
186                     ex.printStackTrace();
187                 }
188                 dlg.dismiss();
189                 final boolean error = _error;
190                 runOnUiThread(new Runnable() {
191                     @Override
192                     public void run() {
193                         AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
194                         builder.setPositiveButton(android.R.string.ok, null);
195                         builder.setTitle(R.string.install);
196                         
197                         if (error) {
198                             builder.setMessage(R.string.install_error);
199                         }
200                         else {
201                             builder.setMessage(R.string.install_success);
202                         }
203                         builder.create().show();
204                     }
205                 });
206             };
207         }.start();
208     }
209     
210     void doInstall() {
211         AlertDialog.Builder builder = new AlertDialog.Builder(this);
212         builder.setTitle(R.string.install);
213         builder.setMessage(R.string.install_superuser_info);
214         builder.setPositiveButton(R.string.install, new OnClickListener() {
215             @Override
216             public void onClick(DialogInterface dialog, int which) {
217                 doSystemInstall();
218             }
219         });
220         builder.setNegativeButton(android.R.string.cancel, null);
221         builder.setNeutralButton(R.string.recovery_install, new OnClickListener() {
222             @Override
223             public void onClick(DialogInterface dialog, int which) {
224                 doRecoveryInstall();
225             }
226         });
227         builder.create().show();
228     }
229     
230     private void saveWhatsNew() {
231         Settings.setString(this, "whats_new", WHATS_NEW);
232     }
233     
234     // this is intentionally not localized as it will change constantly.
235     private static final String WHATS_NEW = "Notifications can now be configured per app.\n\nThe Superuser theme can be configured in Settings.";
236     protected void doWhatsNew() {
237         if (WHATS_NEW.equals(Settings.getString(this, "whats_new")))
238             return;
239         saveWhatsNew();
240         AlertDialog.Builder builder = new AlertDialog.Builder(this);
241         builder.setTitle(R.string.whats_new);
242         builder.setIcon(R.drawable.ic_launcher);
243         builder.setMessage(WHATS_NEW);
244         builder.setPositiveButton(R.string.rate, new OnClickListener() {
245             @Override
246             public void onClick(DialogInterface dialog, int which) {
247                 Intent i = new Intent();
248                 i.setData(Uri.parse("market://details?id=com.koushikdutta.superuser"));
249                 startActivity(i);
250             }
251         });
252         builder.setNegativeButton(android.R.string.cancel, null);
253         builder.create().show();
254     }
255
256     @Override
257     protected void onCreate(Bundle savedInstanceState) {
258         Settings.applyDarkThemeSetting(this, R.style.SuperuserDarkActivity);
259         super.onCreate(savedInstanceState);
260         
261         if (Settings.getBoolean(this, "first_run", true)) {
262             saveWhatsNew();
263             Settings.setBoolean(this, "first_run", false);
264         }
265         
266         final ProgressDialog dlg = new ProgressDialog(this);
267         dlg.setTitle(R.string.superuser);
268         dlg.setMessage(getString(R.string.checking_superuser));
269         dlg.setIndeterminate(true);
270         dlg.show();
271         new Thread() {
272             public void run() {
273                 boolean _error = false;
274                 try {
275                     SuHelper.checkSu(MainActivity.this);
276                 }
277                 catch (Exception e) {
278                     e.printStackTrace();
279                     _error = true;
280                 }
281                 final boolean error = _error;
282                 dlg.dismiss();
283                 runOnUiThread(new Runnable() {
284                     @Override
285                     public void run() {
286                         if (error) {
287                             doInstall();
288                         }
289                         else {
290                             doWhatsNew();
291                         }
292                     }
293                 });
294             };
295         }.start();
296     }
297 }