| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | package com.topjohnwu.magisk.asyncs;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import android.app.Activity;
 | 
					
						
							|  |  |  | import android.net.Uri;
 | 
					
						
							|  |  |  | import android.os.Build;
 | 
					
						
							|  |  |  | import android.os.Environment;
 | 
					
						
							|  |  |  | import android.text.TextUtils;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import com.topjohnwu.magisk.MagiskManager;
 | 
					
						
							|  |  |  | import com.topjohnwu.magisk.utils.AdaptiveList;
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  | import com.topjohnwu.magisk.utils.Shell;
 | 
					
						
							|  |  |  | import com.topjohnwu.magisk.utils.TarEntry;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | import com.topjohnwu.magisk.utils.ZipUtils;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  | import org.kamranzafar.jtar.TarOutputStream;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | import java.io.BufferedInputStream;
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  | import java.io.BufferedOutputStream;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | import java.io.File;
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  | import java.io.FileInputStream;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | import java.io.FileNotFoundException;
 | 
					
						
							|  |  |  | import java.io.FileOutputStream;
 | 
					
						
							|  |  |  | import java.io.IOException;
 | 
					
						
							|  |  |  | import java.io.InputStream;
 | 
					
						
							|  |  |  | import java.io.OutputStream;
 | 
					
						
							|  |  |  | import java.util.Arrays;
 | 
					
						
							|  |  |  | import java.util.List;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  | public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static final int PATCH_MODE = 0;
 | 
					
						
							|  |  |  |     private static final int DIRECT_MODE = 1;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private Uri mBootImg, mZip;
 | 
					
						
							|  |  |  |     private AdaptiveList<String> mList;
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |     private String mBootLocation;
 | 
					
						
							|  |  |  |     private boolean mKeepEnc, mKeepVerity;
 | 
					
						
							|  |  |  |     private int mode;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |     private InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity) {
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |         super(context);
 | 
					
						
							|  |  |  |         mList = list;
 | 
					
						
							|  |  |  |         mZip = zip;
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |         mKeepEnc = enc;
 | 
					
						
							|  |  |  |         mKeepVerity = verity;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity, Uri boot) {
 | 
					
						
							|  |  |  |         this(context, list, zip, enc, verity);
 | 
					
						
							|  |  |  |         mBootImg = boot;
 | 
					
						
							|  |  |  |         mode = PATCH_MODE;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public InstallMagisk(Activity context, AdaptiveList<String> list, Uri zip, boolean enc, boolean verity, String boot) {
 | 
					
						
							|  |  |  |         this(context, list, zip, enc, verity);
 | 
					
						
							|  |  |  |         mBootLocation = boot;
 | 
					
						
							|  |  |  |         mode = DIRECT_MODE;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Override
 | 
					
						
							|  |  |  |     protected void onPreExecute() {
 | 
					
						
							|  |  |  |         // UI updates must run in the UI thread
 | 
					
						
							|  |  |  |         mList.setCallback(this::publishProgress);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Override
 | 
					
						
							|  |  |  |     protected void onProgressUpdate(Void... values) {
 | 
					
						
							|  |  |  |         mList.updateView();
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Override
 | 
					
						
							|  |  |  |     protected Boolean doInBackground(Void... voids) {
 | 
					
						
							| 
									
										
										
										
											2017-09-03 15:35:14 +08:00
										 |  |  |         MagiskManager mm = getMagiskManager();
 | 
					
						
							|  |  |  |         if (mm == null) return false;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 15:35:14 +08:00
										 |  |  |         File install = new File(mm.getApplicationInfo().dataDir, "install");
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |         getShell().sh_raw("rm -rf " + install);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
 | 
					
						
							|  |  |  |         String arch;
 | 
					
						
							|  |  |  |         if (abis.contains("x86_64")) arch = "x64";
 | 
					
						
							|  |  |  |         else if (abis.contains("arm64-v8a")) arch = "arm64";
 | 
					
						
							|  |  |  |         else if (abis.contains("x86")) arch = "x86";
 | 
					
						
							|  |  |  |         else arch = "arm";
 | 
					
						
							|  |  |  |         mList.add("- Device platform: " + arch);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try {
 | 
					
						
							|  |  |  |             // Unzip files
 | 
					
						
							|  |  |  |             mList.add("- Extracting files");
 | 
					
						
							| 
									
										
										
										
											2017-09-03 15:35:14 +08:00
										 |  |  |             try (InputStream in = mm.getContentResolver().openInputStream(mZip)) {
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |                 if (in == null) throw new FileNotFoundException();
 | 
					
						
							|  |  |  |                 BufferedInputStream buf = new BufferedInputStream(in);
 | 
					
						
							|  |  |  |                 buf.mark(Integer.MAX_VALUE);
 | 
					
						
							| 
									
										
										
										
											2017-09-03 21:05:57 +08:00
										 |  |  |                 ZipUtils.unzip(buf, install, arch + "/", true);
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |                 buf.reset();
 | 
					
						
							| 
									
										
										
										
											2017-09-03 21:05:57 +08:00
										 |  |  |                 ZipUtils.unzip(buf, install, "common/", true);
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |                 buf.reset();
 | 
					
						
							| 
									
										
										
										
											2017-09-03 21:05:57 +08:00
										 |  |  |                 ZipUtils.unzip(buf, install, "chromeos/", false);
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |                 buf.reset();
 | 
					
						
							|  |  |  |                 ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true);
 | 
					
						
							|  |  |  |             } catch (FileNotFoundException e) {
 | 
					
						
							|  |  |  |                 mList.add("! Invalid Uri");
 | 
					
						
							|  |  |  |                 throw e;
 | 
					
						
							|  |  |  |             } catch (Exception e) {
 | 
					
						
							|  |  |  |                 mList.add("! Cannot unzip zip");
 | 
					
						
							|  |  |  |                 throw e;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |             File boot;
 | 
					
						
							|  |  |  |             switch (mode) {
 | 
					
						
							|  |  |  |                 case PATCH_MODE:
 | 
					
						
							|  |  |  |                     boot = new File(install, "boot.img");
 | 
					
						
							|  |  |  |                     // Copy boot image to local
 | 
					
						
							|  |  |  |                     try (
 | 
					
						
							| 
									
										
										
										
											2017-09-03 15:35:14 +08:00
										 |  |  |                             InputStream in = mm.getContentResolver().openInputStream(mBootImg);
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |                             OutputStream out = new FileOutputStream(boot);
 | 
					
						
							|  |  |  |                     ) {
 | 
					
						
							|  |  |  |                         if (in == null) throw new FileNotFoundException();
 | 
					
						
							|  |  |  |                         byte buffer[] = new byte[1024];
 | 
					
						
							|  |  |  |                         int length;
 | 
					
						
							|  |  |  |                         while ((length = in.read(buffer)) > 0)
 | 
					
						
							|  |  |  |                             out.write(buffer, 0, length);
 | 
					
						
							|  |  |  |                     } catch (FileNotFoundException e) {
 | 
					
						
							|  |  |  |                         mList.add("! Invalid Uri");
 | 
					
						
							|  |  |  |                         throw e;
 | 
					
						
							|  |  |  |                     } catch (IOException e) {
 | 
					
						
							|  |  |  |                         mList.add("! Copy failed");
 | 
					
						
							|  |  |  |                         throw e;
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							|  |  |  |                 case DIRECT_MODE:
 | 
					
						
							|  |  |  |                     boot = new File(mBootLocation);
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							|  |  |  |                 default:
 | 
					
						
							|  |  |  |                     return false;
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |             }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             mList.add("- Use boot image: " + boot);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Patch boot image
 | 
					
						
							|  |  |  |             getShell().sh(mList,
 | 
					
						
							|  |  |  |                     "cd " + install,
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |                     "KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " +
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  |                             "update-binary indep boot_patch.sh " + boot +
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  |                             " && echo 'Success!' || echo 'Failed!'"
 | 
					
						
							|  |  |  |             );
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
 | 
					
						
							|  |  |  |                 return false;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |             File patched_boot = new File(install, "new-boot.img");
 | 
					
						
							|  |  |  |             mList.add("");
 | 
					
						
							|  |  |  |             switch (mode) {
 | 
					
						
							|  |  |  |                 case PATCH_MODE:
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  |                     File dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/patched_boot" + mm.bootFormat);
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |                     dest.getParentFile().mkdirs();
 | 
					
						
							| 
									
										
										
										
											2017-09-03 17:24:05 +08:00
										 |  |  |                     switch (mm.bootFormat) {
 | 
					
						
							|  |  |  |                         case ".img":
 | 
					
						
							|  |  |  |                             getShell().sh_raw("cp -f " + patched_boot + " " + dest);
 | 
					
						
							|  |  |  |                             break;
 | 
					
						
							|  |  |  |                         case ".img.tar":
 | 
					
						
							|  |  |  |                             // Workaround root shell issues so we can access the file through Java
 | 
					
						
							|  |  |  |                             if (Shell.rootAccess()) {
 | 
					
						
							|  |  |  |                                 // Get non-root UID
 | 
					
						
							|  |  |  |                                 int uid = mm.getApplicationInfo().uid;
 | 
					
						
							|  |  |  |                                 // Get app selabel
 | 
					
						
							|  |  |  |                                 String selabel = getShell().su("/system/bin/ls -dZ " + install + " | cut -d' ' -f1").get(0);
 | 
					
						
							|  |  |  |                                 getShell().su(
 | 
					
						
							|  |  |  |                                         "chcon " + selabel + " " + patched_boot,
 | 
					
						
							|  |  |  |                                         "chown " + uid + "." + uid + " " + patched_boot);
 | 
					
						
							|  |  |  |                             }
 | 
					
						
							|  |  |  |                             TarOutputStream tar = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
 | 
					
						
							|  |  |  |                             tar.putNextEntry(new TarEntry(patched_boot, "boot.img"));
 | 
					
						
							|  |  |  |                             byte buffer[] = new byte[4096];
 | 
					
						
							|  |  |  |                             BufferedInputStream in = new BufferedInputStream(new FileInputStream(patched_boot));
 | 
					
						
							|  |  |  |                             int len;
 | 
					
						
							|  |  |  |                             while ((len = in.read(buffer)) != -1) {
 | 
					
						
							|  |  |  |                                 tar.write(buffer, 0, len);
 | 
					
						
							|  |  |  |                             }
 | 
					
						
							|  |  |  |                             tar.flush();
 | 
					
						
							|  |  |  |                             tar.close();
 | 
					
						
							|  |  |  |                             in.close();
 | 
					
						
							|  |  |  |                             break;
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							| 
									
										
										
										
											2017-09-03 00:10:14 +08:00
										 |  |  |                     mList.add("*********************************");
 | 
					
						
							|  |  |  |                     mList.add(" Patched Boot Image is placed in ");
 | 
					
						
							|  |  |  |                     mList.add(" " + dest + " ");
 | 
					
						
							|  |  |  |                     mList.add("*********************************");
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							|  |  |  |                 case DIRECT_MODE:
 | 
					
						
							|  |  |  |                     // Direct flash boot image
 | 
					
						
							|  |  |  |                     getShell().su_raw("cat " + patched_boot + " /dev/zero | dd of=" + mBootLocation + " bs=4096");
 | 
					
						
							|  |  |  |                     mList.add("Flashing patched boot to " + mBootLocation);
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							|  |  |  |                 default:
 | 
					
						
							|  |  |  |                     return false;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2017-08-31 03:07:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Finals
 | 
					
						
							|  |  |  |             getShell().sh_raw(
 | 
					
						
							|  |  |  |                     "mv bin/busybox busybox",
 | 
					
						
							|  |  |  |                     "rm -rf bin *.img update-binary");
 | 
					
						
							|  |  |  |         } catch (Exception e) {
 | 
					
						
							|  |  |  |             e.printStackTrace();
 | 
					
						
							|  |  |  |             return false;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         return true;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Override
 | 
					
						
							|  |  |  |     protected void onPostExecute(Boolean result) {
 | 
					
						
							|  |  |  |         super.onPostExecute(result);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 |