Skip to content

Commit da42dcd

Browse files
committed
FSTabEntry: getFfMgrFlags() returns list of flags. Rewrite isMultiboot(), 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
1 parent e4b2cdc commit da42dcd

File tree

13 files changed

+287
-26
lines changed

13 files changed

+287
-26
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "sub_projects/Loki"]
2+
path = sub_projects/Loki
3+
url = https://github.com/efidroid/modules_loki.git

app/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ android {
3636
versionNameSuffix "-debug"
3737
}
3838
}
39+
externalNativeBuild {
40+
ndkBuild {
41+
path 'src/main/cpp/Android.mk'
42+
}
43+
}
3944
}
4045

4146
dependencies {

app/src/main/cpp/Android.mk

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
LOCAL_PATH := $(call my-dir)
2+
3+
# LOKI usable only for ARMv7-based phones
4+
ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
5+
LOKI_PATH := $(abspath $(LOCAL_PATH)/../../../../sub_projects/Loki)
6+
7+
include $(CLEAR_VARS)
8+
LOCAL_MODULE := loki_wrapper
9+
LOCAL_SRC_FILES := loki_wrapper.c
10+
LOCAL_STATIC_LIBRARIES := libloki_static
11+
LOCAL_C_INCLUDES += $(LOKI_PATH)
12+
include $(BUILD_SHARED_LIBRARY)
13+
14+
include $(LOKI_PATH)/Android.mk
15+
endif

app/src/main/cpp/loki_wrapper.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <jni.h>
2+
#include <loki.h>
3+
4+
JNIEXPORT jboolean JNICALL
5+
Java_org_efidroid_efidroidmanager_patching_LokiPatcher_nativePatchImage(JNIEnv *env,
6+
jclass class,
7+
jstring imageType_,
8+
jstring aBootImage_,
9+
jstring in_, jstring out_) {
10+
const char *imageType = (*env)->GetStringUTFChars(env, imageType_, 0);
11+
const char *aBootImage = (*env)->GetStringUTFChars(env, aBootImage_, 0);
12+
const char *in = (*env)->GetStringUTFChars(env, in_, 0);
13+
const char *out = (*env)->GetStringUTFChars(env, out_, 0);
14+
15+
// loki_patch() returns '0' on successful exit
16+
int result = loki_patch(imageType, aBootImage, in, out);
17+
18+
(*env)->ReleaseStringUTFChars(env, imageType_, imageType);
19+
(*env)->ReleaseStringUTFChars(env, aBootImage_, aBootImage);
20+
(*env)->ReleaseStringUTFChars(env, in_, in);
21+
(*env)->ReleaseStringUTFChars(env, out_, out);
22+
23+
return (jboolean)(result == 0);
24+
}

app/src/main/java/org/efidroid/efidroidmanager/RootToolsEx.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -676,14 +676,7 @@ public static void init(Context context) {
676676
int lastVersionCode = sp.getInt(AppConstants.SHAREDPREFS_GLOBAL_LAST_APP_VERSION, 0);
677677

678678
try {
679-
ArrayList<String> abis = new ArrayList<>();
680-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
681-
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
682-
}
683-
else {
684-
abis.add(Build.CPU_ABI);
685-
abis.add(Build.CPU_ABI2);
686-
}
679+
List<String> abis = Util.getABIs();
687680

688681
InputStream is = null;
689682
for(String abi : abis) {

app/src/main/java/org/efidroid/efidroidmanager/Util.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.content.Context;
66
import android.content.res.TypedArray;
77
import android.graphics.Bitmap;
8+
import android.os.Build;
89
import android.support.design.widget.AppBarLayout;
910
import android.util.TypedValue;
1011
import android.view.View;
@@ -20,6 +21,8 @@
2021
import java.nio.ByteBuffer;
2122
import java.nio.ByteOrder;
2223
import java.util.ArrayList;
24+
import java.util.Arrays;
25+
import java.util.List;
2326

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

41+
public static List<String> getABIs() {
42+
ArrayList<String> abis = new ArrayList<>();
43+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
44+
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
45+
}
46+
else {
47+
abis.add(Build.CPU_ABI);
48+
abis.add(Build.CPU_ABI2);
49+
}
50+
return abis;
51+
}
52+
3853
public static byte[] longToBytes(long x) {
3954
ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE/Byte.SIZE);
4055
buffer.order(ByteOrder.LITTLE_ENDIAN);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.efidroid.efidroidmanager.patching;
2+
3+
4+
import android.content.Context;
5+
6+
import org.efidroid.efidroidmanager.models.DeviceInfo;
7+
import org.efidroid.efidroidmanager.types.FSTabEntry;
8+
9+
final class DummyPatcher extends Patcher {
10+
DummyPatcher(DeviceInfo deviceInfo, Context context) {
11+
super(deviceInfo, context);
12+
}
13+
14+
@Override
15+
public void prepareEnvironment(String updateDir) throws Exception {
16+
17+
}
18+
19+
@Override
20+
public boolean isPatchRequired(FSTabEntry entry) {
21+
return false;
22+
}
23+
24+
@Override
25+
public void patchImage(FSTabEntry destEntry, String image) throws Exception {
26+
27+
}
28+
29+
@Override
30+
public void cleanupEnvironment() {
31+
32+
}
33+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.efidroid.efidroidmanager.patching;
2+
3+
import android.content.Context;
4+
5+
import com.stericson.roottools.RootTools;
6+
7+
import org.efidroid.efidroidmanager.RootToolsEx;
8+
import org.efidroid.efidroidmanager.Util;
9+
import org.efidroid.efidroidmanager.models.DeviceInfo;
10+
import org.efidroid.efidroidmanager.types.FSTabEntry;
11+
12+
import java.util.List;
13+
14+
class LokiPatcher extends Patcher {
15+
private enum ImageType {
16+
BOOT("boot","lokiboot"),
17+
RECOVERY("recovery", "lokirecovery");
18+
19+
private final String mName, mFlag;
20+
21+
ImageType(String name, String flag) {
22+
mName = name;
23+
mFlag = flag;
24+
}
25+
26+
String getName() { return mName; }
27+
28+
String getFlag() { return mFlag; }
29+
}
30+
31+
static {
32+
// LOKI usable only for ARMv7-based phones
33+
List<String> abis = Util.getABIs();
34+
if (abis.contains("armeabi-v7a")) {
35+
System.loadLibrary("loki_wrapper");
36+
for (ImageType imageType : ImageType.values()) {
37+
PatcherStorage.registerPatcher(imageType.getFlag(), LokiPatcher.class);
38+
}
39+
}
40+
}
41+
42+
private static final String ABootFlag = "lokiaboot";
43+
44+
private String aBootImage;
45+
46+
public LokiPatcher(DeviceInfo deviceInfo, Context context) {
47+
super(deviceInfo, context);
48+
}
49+
50+
@Override
51+
public void prepareEnvironment(String updateDir) throws Exception {
52+
FSTabEntry aBootEntry = null;
53+
for (FSTabEntry entry : getDeviceInfo().getFSTab().getFSTabEntries()) {
54+
if (entry.getFfMgrFlags().contains(ABootFlag)) {
55+
aBootEntry = entry;
56+
}
57+
}
58+
if (aBootEntry == null) {
59+
throw new Exception("ABoot "+ABootFlag+" entry not found (bad multiboot.fstab)");
60+
}
61+
aBootImage = updateDir + "/aboot.img";
62+
RootToolsEx.dd(aBootEntry.getBlkDevice(),aBootImage);
63+
}
64+
65+
@Override
66+
public boolean isPatchRequired(FSTabEntry entry) {
67+
for (ImageType imageType : ImageType.values()) {
68+
if (entry.getFfMgrFlags().contains(imageType.getFlag())) {
69+
return true;
70+
}
71+
}
72+
return false;
73+
}
74+
75+
private static native boolean nativePatchImage(String imageType, String aBootImage, String in, String out);
76+
77+
@Override
78+
public void patchImage(FSTabEntry destEntry, String image) throws Exception {
79+
boolean isSuccessfulPatch = false;
80+
String outputImage = null;
81+
for (ImageType imageType : ImageType.values()) {
82+
if (destEntry.getFfMgrFlags().contains(imageType.getFlag())) {
83+
outputImage = image.substring(0, image.lastIndexOf('/')) + "/" + imageType.getName() + ".img";
84+
isSuccessfulPatch = nativePatchImage(imageType.getName(), aBootImage, image, outputImage);
85+
}
86+
}
87+
if (isSuccessfulPatch) {
88+
RootTools.copyFile(outputImage, image, false, true);
89+
RootTools.deleteFileOrDirectory(outputImage, false);
90+
} else {
91+
throw new Exception("Image patch error");
92+
}
93+
}
94+
95+
@Override
96+
public void cleanupEnvironment() {
97+
RootTools.deleteFileOrDirectory(aBootImage, false);
98+
}
99+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.efidroid.efidroidmanager.patching;
2+
3+
import android.content.Context;
4+
5+
import org.efidroid.efidroidmanager.models.DeviceInfo;
6+
import org.efidroid.efidroidmanager.types.FSTabEntry;
7+
8+
public abstract class Patcher {
9+
private final Context mContext;
10+
private final DeviceInfo mDeviceInfo;
11+
12+
Patcher(DeviceInfo deviceInfo, Context context) {
13+
mContext = context;
14+
mDeviceInfo = deviceInfo;
15+
}
16+
17+
protected Context getContext() { return mContext; }
18+
19+
protected DeviceInfo getDeviceInfo() { return mDeviceInfo; }
20+
21+
public abstract void prepareEnvironment(String updateDir) throws Exception;
22+
23+
public abstract boolean isPatchRequired(FSTabEntry entry);
24+
25+
// replaces original image with patched
26+
public abstract void patchImage(FSTabEntry destEntry, String image) throws Exception;
27+
28+
public abstract void cleanupEnvironment();
29+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.efidroid.efidroidmanager.patching;
2+
3+
import android.content.Context;
4+
5+
import org.efidroid.efidroidmanager.models.DeviceInfo;
6+
import org.efidroid.efidroidmanager.types.FSTabEntry;
7+
8+
import java.lang.reflect.Constructor;
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
12+
public final class PatcherStorage {
13+
// FSTab flag to patcher
14+
private static final Map<String, Class<? extends Patcher>> patchers = new HashMap<>();
15+
16+
static void registerPatcher(String flag, Class<? extends Patcher> patcher) {
17+
patchers.put(flag,patcher);
18+
}
19+
20+
// selects patcher using FSTab flags. If no patcher selected, returns a DummyPatcher instance
21+
public static Patcher selectPatcher(DeviceInfo deviceInfo, Context context) throws Exception{
22+
for (FSTabEntry entry : deviceInfo.getFSTab().getFSTabEntries()) {
23+
for (String flag : patchers.keySet()) {
24+
if (entry.getFfMgrFlags().contains(flag)) {
25+
Class<? extends Patcher> patcherClass = patchers.get(flag);
26+
if (patcherClass==null) {
27+
throw new Exception("Patcher registered but not found");
28+
}
29+
try {
30+
Constructor constructor = patcherClass.getDeclaredConstructor(DeviceInfo.class, Context.class);
31+
return (Patcher) constructor.newInstance(deviceInfo, context);
32+
} catch (NoSuchMethodException e) {
33+
throw new Exception("Cannot instantiate patcher");
34+
}
35+
}
36+
}
37+
}
38+
return new DummyPatcher(deviceInfo, context);
39+
}
40+
41+
private PatcherStorage() {}
42+
}

0 commit comments

Comments
 (0)