Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LOKI support #11

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,103 @@
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,33 @@
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,43 @@
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