Skip to content

Commit

Permalink
FSTabEntry: getFfMgrFlags() returns list of flags. Rewrite isMultiboo…
Browse files Browse the repository at this point in the history
…t(), isUEFI(), getESP() using it

Move ABIs retrieving code to separate method getABIs() in Util

Add universal image patching interface
Add image patching (if needed) before flashing.
Add LOKI as git submodule
Add LOKI image patcher using NDK
  • Loading branch information
xakep666 committed Feb 13, 2017
1 parent e4b2cdc commit da42dcd
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 26 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "sub_projects/Loki"]
path = sub_projects/Loki
url = https://github.com/efidroid/modules_loki.git
5 changes: 5 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ android {
versionNameSuffix "-debug"
}
}
externalNativeBuild {
ndkBuild {
path 'src/main/cpp/Android.mk'
}
}
}

dependencies {
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/cpp/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
LOCAL_PATH := $(call my-dir)

# LOKI usable only for ARMv7-based phones
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
LOKI_PATH := $(abspath $(LOCAL_PATH)/../../../../sub_projects/Loki)

include $(CLEAR_VARS)
LOCAL_MODULE := loki_wrapper
LOCAL_SRC_FILES := loki_wrapper.c
LOCAL_STATIC_LIBRARIES := libloki_static
LOCAL_C_INCLUDES += $(LOKI_PATH)
include $(BUILD_SHARED_LIBRARY)

include $(LOKI_PATH)/Android.mk
endif
24 changes: 24 additions & 0 deletions app/src/main/cpp/loki_wrapper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <jni.h>
#include <loki.h>

JNIEXPORT jboolean JNICALL
Java_org_efidroid_efidroidmanager_patching_LokiPatcher_nativePatchImage(JNIEnv *env,
jclass class,
jstring imageType_,
jstring aBootImage_,
jstring in_, jstring out_) {
const char *imageType = (*env)->GetStringUTFChars(env, imageType_, 0);
const char *aBootImage = (*env)->GetStringUTFChars(env, aBootImage_, 0);
const char *in = (*env)->GetStringUTFChars(env, in_, 0);
const char *out = (*env)->GetStringUTFChars(env, out_, 0);

// loki_patch() returns '0' on successful exit
int result = loki_patch(imageType, aBootImage, in, out);

(*env)->ReleaseStringUTFChars(env, imageType_, imageType);
(*env)->ReleaseStringUTFChars(env, aBootImage_, aBootImage);
(*env)->ReleaseStringUTFChars(env, in_, in);
(*env)->ReleaseStringUTFChars(env, out_, out);

return (jboolean)(result == 0);
}
Original file line number Diff line number Diff line change
Expand Up @@ -676,14 +676,7 @@ public static void init(Context context) {
int lastVersionCode = sp.getInt(AppConstants.SHAREDPREFS_GLOBAL_LAST_APP_VERSION, 0);

try {
ArrayList<String> abis = new ArrayList<>();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
}
else {
abis.add(Build.CPU_ABI);
abis.add(Build.CPU_ABI2);
}
List<String> abis = Util.getABIs();

InputStream is = null;
for(String abi : abis) {
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/java/org/efidroid/efidroidmanager/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.design.widget.AppBarLayout;
import android.util.TypedValue;
import android.view.View;
Expand All @@ -20,6 +21,8 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Util {
public static OperatingSystemEditActivity.MultibootPartitionInfo getPartitionInfoByName(ArrayList<OperatingSystemEditActivity.MultibootPartitionInfo> list, String name) {
Expand All @@ -35,6 +38,18 @@ public static String name2path(String name) {
return name.replaceAll("\\W+", "_");
}

public static List<String> getABIs() {
ArrayList<String> abis = new ArrayList<>();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
}
else {
abis.add(Build.CPU_ABI);
abis.add(Build.CPU_ABI2);
}
return abis;
}

public static byte[] longToBytes(long x) {
ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE/Byte.SIZE);
buffer.order(ByteOrder.LITTLE_ENDIAN);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.efidroid.efidroidmanager.patching;


import android.content.Context;

import org.efidroid.efidroidmanager.models.DeviceInfo;
import org.efidroid.efidroidmanager.types.FSTabEntry;

final class DummyPatcher extends Patcher {
DummyPatcher(DeviceInfo deviceInfo, Context context) {
super(deviceInfo, context);
}

@Override
public void prepareEnvironment(String updateDir) throws Exception {

}

@Override
public boolean isPatchRequired(FSTabEntry entry) {
return false;
}

@Override
public void patchImage(FSTabEntry destEntry, String image) throws Exception {

}

@Override
public void cleanupEnvironment() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.efidroid.efidroidmanager.patching;

import android.content.Context;

import com.stericson.roottools.RootTools;

import org.efidroid.efidroidmanager.RootToolsEx;
import org.efidroid.efidroidmanager.Util;
import org.efidroid.efidroidmanager.models.DeviceInfo;
import org.efidroid.efidroidmanager.types.FSTabEntry;

import java.util.List;

class LokiPatcher extends Patcher {
private enum ImageType {
BOOT("boot","lokiboot"),
RECOVERY("recovery", "lokirecovery");

private final String mName, mFlag;

ImageType(String name, String flag) {
mName = name;
mFlag = flag;
}

String getName() { return mName; }

String getFlag() { return mFlag; }
}

static {
// LOKI usable only for ARMv7-based phones
List<String> abis = Util.getABIs();
if (abis.contains("armeabi-v7a")) {
System.loadLibrary("loki_wrapper");
for (ImageType imageType : ImageType.values()) {
PatcherStorage.registerPatcher(imageType.getFlag(), LokiPatcher.class);
}
}
}

private static final String ABootFlag = "lokiaboot";

private String aBootImage;

public LokiPatcher(DeviceInfo deviceInfo, Context context) {
super(deviceInfo, context);
}

@Override
public void prepareEnvironment(String updateDir) throws Exception {
FSTabEntry aBootEntry = null;
for (FSTabEntry entry : getDeviceInfo().getFSTab().getFSTabEntries()) {
if (entry.getFfMgrFlags().contains(ABootFlag)) {
aBootEntry = entry;
}
}
if (aBootEntry == null) {
throw new Exception("ABoot "+ABootFlag+" entry not found (bad multiboot.fstab)");
}
aBootImage = updateDir + "/aboot.img";
RootToolsEx.dd(aBootEntry.getBlkDevice(),aBootImage);
}

@Override
public boolean isPatchRequired(FSTabEntry entry) {
for (ImageType imageType : ImageType.values()) {
if (entry.getFfMgrFlags().contains(imageType.getFlag())) {
return true;
}
}
return false;
}

private static native boolean nativePatchImage(String imageType, String aBootImage, String in, String out);

@Override
public void patchImage(FSTabEntry destEntry, String image) throws Exception {
boolean isSuccessfulPatch = false;
String outputImage = null;
for (ImageType imageType : ImageType.values()) {
if (destEntry.getFfMgrFlags().contains(imageType.getFlag())) {
outputImage = image.substring(0, image.lastIndexOf('/')) + "/" + imageType.getName() + ".img";
isSuccessfulPatch = nativePatchImage(imageType.getName(), aBootImage, image, outputImage);
}
}
if (isSuccessfulPatch) {
RootTools.copyFile(outputImage, image, false, true);
RootTools.deleteFileOrDirectory(outputImage, false);
} else {
throw new Exception("Image patch error");
}
}

@Override
public void cleanupEnvironment() {
RootTools.deleteFileOrDirectory(aBootImage, false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.efidroid.efidroidmanager.patching;

import android.content.Context;

import org.efidroid.efidroidmanager.models.DeviceInfo;
import org.efidroid.efidroidmanager.types.FSTabEntry;

public abstract class Patcher {
private final Context mContext;
private final DeviceInfo mDeviceInfo;

Patcher(DeviceInfo deviceInfo, Context context) {
mContext = context;
mDeviceInfo = deviceInfo;
}

protected Context getContext() { return mContext; }

protected DeviceInfo getDeviceInfo() { return mDeviceInfo; }

public abstract void prepareEnvironment(String updateDir) throws Exception;

public abstract boolean isPatchRequired(FSTabEntry entry);

// replaces original image with patched
public abstract void patchImage(FSTabEntry destEntry, String image) throws Exception;

public abstract void cleanupEnvironment();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.efidroid.efidroidmanager.patching;

import android.content.Context;

import org.efidroid.efidroidmanager.models.DeviceInfo;
import org.efidroid.efidroidmanager.types.FSTabEntry;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public final class PatcherStorage {
// FSTab flag to patcher
private static final Map<String, Class<? extends Patcher>> patchers = new HashMap<>();

static void registerPatcher(String flag, Class<? extends Patcher> patcher) {
patchers.put(flag,patcher);
}

// selects patcher using FSTab flags. If no patcher selected, returns a DummyPatcher instance
public static Patcher selectPatcher(DeviceInfo deviceInfo, Context context) throws Exception{
for (FSTabEntry entry : deviceInfo.getFSTab().getFSTabEntries()) {
for (String flag : patchers.keySet()) {
if (entry.getFfMgrFlags().contains(flag)) {
Class<? extends Patcher> patcherClass = patchers.get(flag);
if (patcherClass==null) {
throw new Exception("Patcher registered but not found");
}
try {
Constructor constructor = patcherClass.getDeclaredConstructor(DeviceInfo.class, Context.class);
return (Patcher) constructor.newInstance(deviceInfo, context);
} catch (NoSuchMethodException e) {
throw new Exception("Cannot instantiate patcher");
}
}
}
}
return new DummyPatcher(deviceInfo, context);
}

private PatcherStorage() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.efidroid.efidroidmanager.RootToolsEx;
import org.efidroid.efidroidmanager.Util;
import org.efidroid.efidroidmanager.models.DeviceInfo;
import org.efidroid.efidroidmanager.patching.Patcher;
import org.efidroid.efidroidmanager.patching.PatcherStorage;
import org.efidroid.efidroidmanager.services.GenericProgressIntentService;
import org.efidroid.efidroidmanager.types.FSTabEntry;
import org.efidroid.efidroidmanager.types.InstallationEntry;
Expand Down Expand Up @@ -115,6 +117,9 @@ private String downloadUpdate(String urlString) throws Exception {
}

private void doInstall(String updateDir) throws Exception {
// determine appropriate patcher
Patcher patcher = PatcherStorage.selectPatcher(mDeviceInfo, getService().getApplicationContext());

// get esp parent directory
String espParent = mDeviceInfo.getESPDir(false);
if (espParent == null)
Expand Down Expand Up @@ -161,14 +166,21 @@ private void doInstall(String updateDir) throws Exception {
}
}

patcher.prepareEnvironment(updateDir);

// install
for (FSTabEntry entry : mDeviceInfo.getFSTab().getFSTabEntries()) {
if (!entry.isUEFI())
continue;

String file = updateDir + "/" + entry.getName() + ".img";
if (patcher.isPatchRequired(entry)) {
patcher.patchImage(entry, file);
}
RootToolsEx.dd(file, entry.getBlkDevice());
}

patcher.cleanupEnvironment();
}

public void onProcess(Bundle extras) {
Expand Down
Loading

0 comments on commit da42dcd

Please sign in to comment.