Commit db8fd2c9 authored by topjohnwu's avatar topjohnwu

Add boot image file patch

parent dbe6e5b3
package com.topjohnwu.magisk; package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
...@@ -8,12 +9,17 @@ import android.support.v7.widget.Toolbar; ...@@ -8,12 +9,17 @@ import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.FlashZip; import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.asyncs.PatchBootImage;
import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.AdaptiveList; import com.topjohnwu.magisk.utils.AdaptiveList;
import com.topjohnwu.magisk.utils.Shell;
import java.util.List;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
...@@ -21,11 +27,15 @@ import butterknife.OnClick; ...@@ -21,11 +27,15 @@ import butterknife.OnClick;
public class FlashActivity extends Activity { public class FlashActivity extends Activity {
public static final String SET_ACTION = "action";
public static final String SET_BOOT_URI = "boot_uri";
public static final String FLASH_ZIP = "flash";
public static final String PATCH_BOOT = "patch";
@BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.flash_logs) RecyclerView flashLogs; @BindView(R.id.flash_logs) RecyclerView flashLogs;
@BindView(R.id.button_panel) LinearLayout buttonPanel; @BindView(R.id.button_panel) LinearLayout buttonPanel;
@BindView(R.id.reboot) Button reboot;
private AdaptiveList<String> rootShellOutput;
@OnClick(R.id.no_thanks) @OnClick(R.id.no_thanks)
public void dismiss() { public void dismiss() {
...@@ -42,22 +52,33 @@ public class FlashActivity extends Activity { ...@@ -42,22 +52,33 @@ public class FlashActivity extends Activity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flash); setContentView(R.layout.activity_flash);
ButterKnife.bind(this); ButterKnife.bind(this);
rootShellOutput = new AdaptiveList<>(flashLogs); AdaptiveList<String> rootShellOutput = new AdaptiveList<>(flashLogs);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar(); ActionBar ab = getSupportActionBar();
if (ab != null) { if (ab != null) {
ab.setTitle(R.string.flashing); ab.setTitle(R.string.flashing);
} }
setFloating(); setFloating();
if (!Shell.rootAccess())
reboot.setVisibility(View.GONE);
flashLogs.setAdapter(new FlashLogAdapter()); flashLogs.setAdapter(new FlashLogAdapter(rootShellOutput));
// We must receive a Uri of the target zip // We must receive a Uri of the target zip
Uri uri = getIntent().getData(); Intent intent = getIntent();
Uri uri = intent.getData();
new FlashZip(this, uri, rootShellOutput)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) switch (getIntent().getStringExtra(SET_ACTION)) {
.exec(); case FLASH_ZIP:
new FlashZip(this, uri, rootShellOutput)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
.exec();
break;
case PATCH_BOOT:
new PatchBootImage(this, uri, intent.getParcelableExtra(SET_BOOT_URI), rootShellOutput)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
.exec();
}
} }
@Override @Override
...@@ -65,7 +86,13 @@ public class FlashActivity extends Activity { ...@@ -65,7 +86,13 @@ public class FlashActivity extends Activity {
// Prevent user accidentally press back button // Prevent user accidentally press back button
} }
private class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> { private static class FlashLogAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<String> mList;
FlashLogAdapter(List<String> list) {
mList = list;
}
@Override @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...@@ -76,16 +103,16 @@ public class FlashActivity extends Activity { ...@@ -76,16 +103,16 @@ public class FlashActivity extends Activity {
@Override @Override
public void onBindViewHolder(ViewHolder holder, int position) { public void onBindViewHolder(ViewHolder holder, int position) {
holder.text.setText(rootShellOutput.get(position)); holder.text.setText(mList.get(position));
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return rootShellOutput.size(); return mList.size();
} }
} }
public class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.textView) TextView text; @BindView(R.id.textView) TextView text;
......
...@@ -87,7 +87,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber { ...@@ -87,7 +87,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) { if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) {
// Get the URI of the selected file // Get the URI of the selected file
Intent intent = new Intent(getActivity(), FlashActivity.class); Intent intent = new Intent(getActivity(), FlashActivity.class);
intent.setData(data.getData()).putExtra("ACTION", "flash"); intent.setData(data.getData()).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP);
startActivity(intent); startActivity(intent);
} }
} }
......
...@@ -139,6 +139,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { ...@@ -139,6 +139,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
if (!Shell.rootAccess()) { if (!Shell.rootAccess()) {
prefScreen.removePreference(magiskCategory); prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory); prefScreen.removePreference(suCategory);
generalCatagory.removePreference(hideManager);
} else { } else {
if (!magiskManager.isSuClient) { if (!magiskManager.isSuClient) {
prefScreen.removePreference(suCategory); prefScreen.removePreference(suCategory);
......
...@@ -18,7 +18,7 @@ import java.io.InputStream; ...@@ -18,7 +18,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List; import java.util.List;
public class FlashZip extends ParallelTask<Void, String, Integer> { public class FlashZip extends ParallelTask<Void, Void, Integer> {
private Uri mUri; private Uri mUri;
private File mCachedFile, mScriptFile, mCheckFile; private File mCachedFile, mScriptFile, mCheckFile;
...@@ -40,7 +40,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { ...@@ -40,7 +40,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
} }
private boolean unzipAndCheck() throws Exception { private boolean unzipAndCheck() throws Exception {
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android"); ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", false);
List<String> ret = Utils.readFile(getShell(), mCheckFile.getPath()); List<String> ret = Utils.readFile(getShell(), mCheckFile.getPath());
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK"); return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
} }
...@@ -52,7 +52,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { ...@@ -52,7 +52,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
} }
@Override @Override
protected void onProgressUpdate(String... values) { protected void onProgressUpdate(Void... values) {
mList.updateView(); mList.updateView();
} }
...@@ -61,18 +61,18 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { ...@@ -61,18 +61,18 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
MagiskManager magiskManager = getMagiskManager(); MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return -1; if (magiskManager == null) return -1;
try { try {
mList.add(magiskManager.getString(R.string.copying_msg)); mList.add("- Copying zip to temp directory");
mCachedFile.delete(); mCachedFile.delete();
try ( try (
InputStream in = magiskManager.getContentResolver().openInputStream(mUri); InputStream in = magiskManager.getContentResolver().openInputStream(mUri);
OutputStream outputStream = new FileOutputStream(mCachedFile) OutputStream out = new FileOutputStream(mCachedFile)
) { ) {
if (in == null) throw new FileNotFoundException(); if (in == null) throw new FileNotFoundException();
byte buffer[] = new byte[1024]; byte buffer[] = new byte[1024];
int length; int length;
while ((length = in.read(buffer)) > 0) while ((length = in.read(buffer)) > 0)
outputStream.write(buffer, 0, length); out.write(buffer, 0, length);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
mList.add("! Invalid Uri"); mList.add("! Invalid Uri");
throw e; throw e;
...@@ -81,7 +81,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> { ...@@ -81,7 +81,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
throw e; throw e;
} }
if (!unzipAndCheck()) return 0; if (!unzipAndCheck()) return 0;
mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename)); mList.add("- Installing " + mFilename);
getShell().su(mList, getShell().su(mList,
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile + "BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
" && echo 'Success!' || echo 'Failed!'" " && echo 'Success!' || echo 'Failed!'"
......
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;
import com.topjohnwu.magisk.utils.ZipUtils;
import java.io.BufferedInputStream;
import java.io.File;
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;
public class PatchBootImage extends ParallelTask<Void, Void, Boolean> {
private Uri mBootImg, mZip;
private AdaptiveList<String> mList;
private File dest;
public PatchBootImage(Activity context, Uri zip, Uri boot, AdaptiveList<String> list) {
super(context);
mBootImg = boot;
mList = list;
mZip = zip;
dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/" + "patched_boot.img");
}
@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) {
MagiskManager magiskManager = getMagiskManager();
if (magiskManager == null) return false;
File install = new File(magiskManager.getApplicationInfo().dataDir, "install");
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");
try (InputStream in = magiskManager.getContentResolver().openInputStream(mZip)) {
if (in == null) throw new FileNotFoundException();
BufferedInputStream buf = new BufferedInputStream(in);
buf.mark(Integer.MAX_VALUE);
ZipUtils.unzip(buf, install, arch, true);
buf.reset();
ZipUtils.unzip(buf, install, "common", true);
buf.reset();
ZipUtils.unzip(buf, install, "chromeos", false);
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;
}
// Copy boot image
File boot = new File(install, "boot.img");
try (
InputStream in = magiskManager.getContentResolver().openInputStream(mBootImg);
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;
}
mList.add("- Use boot image: " + boot);
// Patch boot image
getShell().sh(mList,
"chmod -R 755 " + install,
"cd " + install,
"sh update-binary indep boot_patch.sh " + boot +
" && echo 'Success!' || echo 'Failed!'"
);
if (!TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
return false;
// Move boot image
File source = new File(install, "new-boot.img");
dest.getParentFile().mkdirs();
getShell().sh_raw("mv " + source + " " + dest);
// 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) {
if (result) {
mList.add("");
mList.add("*********************************");
mList.add(" Patched Boot Image is placed in ");
mList.add(" " + dest + " ");
mList.add("*********************************");
}
super.onPostExecute(result);
}
}
...@@ -94,12 +94,15 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> { ...@@ -94,12 +94,15 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
progressDialog.dismiss(); progressDialog.dismiss();
if (result) { if (result) {
if (Shell.rootAccess() && mInstall) { if (Shell.rootAccess() && mInstall) {
activity.startActivity(new Intent(activity, FlashActivity.class).setData(mUri)); Intent intent = new Intent(getActivity(), FlashActivity.class);
intent.setData(mUri).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP);
activity.startActivity(intent);
} else { } else {
Utils.showUriSnack(activity, mUri); Utils.showUriSnack(activity, mUri);
} }
} else { } else {
Utils.getMagiskManager(activity).toast(R.string.process_error, Toast.LENGTH_LONG); Utils.getMagiskManager(activity).toast(R.string.process_error, Toast.LENGTH_LONG);
} }
super.onPostExecute(result);
} }
} }
...@@ -156,34 +156,38 @@ public class ZipUtils { ...@@ -156,34 +156,38 @@ public class ZipUtils {
} }
} }
public static void unzip(File file, File folder, String path) throws Exception { public static void unzip(File zip, File folder, String path, boolean junkPath) throws Exception {
int count; JarInputStream in = new JarInputStream(new FileInputStream(zip));
FileOutputStream out; unzip(in, folder, path, junkPath);
File dest; in.close();
InputStream is; }
JarEntry entry;
public static void unzip(InputStream zip, File folder, String path, boolean junkPath) throws Exception {
byte data[] = new byte[4096]; byte data[] = new byte[4096];
try (JarFile zipfile = new JarFile(file)) { try {
Enumeration<JarEntry> e = zipfile.entries(); JarInputStream zipfile = new JarInputStream(zip);
while(e.hasMoreElements()) { JarEntry entry;
entry = e.nextElement(); while ((entry = zipfile.getNextJarEntry()) != null) {
if (!entry.getName().contains(path) || entry.isDirectory()){ if (!entry.getName().startsWith(path) || entry.isDirectory()){
// Ignore directories, only create files // Ignore directories, only create files
continue; continue;
} }
Logger.dev("ZipUtils: Extracting: " + entry); String name;
is = zipfile.getInputStream(entry); if (junkPath) {
dest = new File(folder, entry.getName()); name = entry.getName().substring(entry.getName().lastIndexOf('/') + 1);
if (dest.getParentFile().mkdirs()) { } else {
dest.createNewFile(); name = entry.getName();
} }
out = new FileOutputStream(dest); Logger.dev("ZipUtils: Extracting: " + entry);
while ((count = is.read(data)) != -1) { File dest = new File(folder, name);
dest.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(dest);
int count;
while ((count = zipfile.read(data)) != -1) {
out.write(data, 0, count); out.write(data, 0, count);
} }
out.flush(); out.flush();
out.close(); out.close();
is.close();
} }
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
......
...@@ -138,6 +138,10 @@ ...@@ -138,6 +138,10 @@
<string name="flashing">Flashing</string> <string name="flashing">Flashing</string>
<string name="hide_manager_toast">Hiding Magisk Manager…</string> <string name="hide_manager_toast">Hiding Magisk Manager…</string>
<string name="hide_manager_fail_toast">Hide Magisk Manager failed…</string> <string name="hide_manager_fail_toast">Hide Magisk Manager failed…</string>
<string name="download_zip_only">Download Zip Only</string>
<string name="patch_boot_file">Patch Boot Image File</string>
<string name="direct_install">Direct Install (Recommend)</string>
<string name="select_method">Select Method</string>
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">General</string> <string name="settings_general_category">General</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment