com.github.chenxiaolong.dualbootpatcher.settings.RomSettingsUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.github.chenxiaolong.dualbootpatcher.settings.RomSettingsUtils.java

Source

/*
 * Copyright (C) 2014-2015  Andrew Gunnerson <andrewgunnerson@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.github.chenxiaolong.dualbootpatcher.settings;

import android.content.Context;
import android.util.Log;

import com.github.chenxiaolong.dualbootpatcher.BuildConfig;
import com.github.chenxiaolong.dualbootpatcher.LogUtils;
import com.github.chenxiaolong.dualbootpatcher.RomUtils;
import com.github.chenxiaolong.dualbootpatcher.RomUtils.RomInformation;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.BootImage;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.BootImage.Type;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.CpioFile;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.Device;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.FileInfo;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.Patcher;
import com.github.chenxiaolong.dualbootpatcher.patcher.PatcherUtils;
import com.github.chenxiaolong.dualbootpatcher.socket.MbtoolSocket;
import com.github.chenxiaolong.dualbootpatcher.socket.MbtoolSocket.SetKernelResult;
import com.github.chenxiaolong.dualbootpatcher.socket.MbtoolSocket.SwitchRomResult;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;

public class RomSettingsUtils {
    private static final String TAG = RomSettingsUtils.class.getSimpleName();

    private static final String ABOOT_PARTITION = "/dev/block/platform/msm_sdcc.1/by-name/aboot";

    /**
     * Update mbtool using libmbp and return the path to the new boot image
     *
     * @return New file path on success or null on error
     */
    private static String updateMbtool(Context context, String path) {
        PatcherUtils.initializePatcher(context);

        Patcher patcher = PatcherUtils.sPC.createPatcher("MbtoolUpdater");
        if (patcher == null) {
            Log.e(TAG, "Bundled libmbp does not support MbtoolUpdater!");
            return null;
        }

        FileInfo fi = new FileInfo();
        fi.setFilename(path);

        Device device = PatcherUtils.getCurrentDevice(context, PatcherUtils.sPC);
        String codename = RomUtils.getDeviceCodename(context);
        if (device == null) {
            Log.e(TAG, "Current device " + codename + " does not appear to be supported");
            return null;
        }
        fi.setDevice(device);

        patcher.setFileInfo(fi);

        if (!patcher.patchFile(null)) {
            logLibMbpError(context, patcher.getError());
            PatcherUtils.sPC.destroyPatcher(patcher);
            return null;
        }

        String newPath = patcher.newFilePath();
        PatcherUtils.sPC.destroyPatcher(patcher);
        return newPath;
    }

    /**
     * Log the libmbp error and destoy the PatcherError object
     *
     * @param context Context
     * @param error PatcherError
     */
    private static void logLibMbpError(Context context, int error) {
        Log.e(TAG, "libmbp error code: " + error);
    }

    public synchronized static boolean updateRamdisk(Context context) {
        Log.d(TAG, "Starting to update ramdisk to " + BuildConfig.VERSION_NAME);

        try {
            // libmbp's MbtoolUpdater needs to grab a copy of the latest mbtool from the
            // data archive

            PatcherUtils.extractPatcher(context);

            // We'll need to add the ROM ID to the kernel command line
            RomInformation romInfo = RomUtils.getCurrentRom(context);
            if (romInfo == null) {
                Log.e(TAG, "Could not determine current ROM");
                return false;
            }

            String bootImage = RomUtils.getBootImagePath(romInfo.getId());
            File bootImageFile = new File(bootImage);

            // Make sure the kernel was backed up
            if (!bootImageFile.exists()) {
                try {
                    SetKernelResult result = MbtoolSocket.getInstance().setKernel(context, romInfo.getId());
                    if (result != SetKernelResult.SUCCEEDED) {
                        Log.e(TAG, "Failed to backup boot image before modification");
                        return false;
                    }
                } catch (IOException e) {
                    Log.e(TAG, "mbtool communication error", e);
                    return false;
                }
            }

            String bootImageBackup = bootImage + ".before-ramdisk-update.img";
            File bootImageBackupFile = new File(bootImageBackup);

            try {
                org.apache.commons.io.FileUtils.copyFile(bootImageFile, bootImageBackupFile);
            } catch (IOException e) {
                Log.w(TAG, "Failed to copy " + bootImage + " to " + bootImageBackupFile, e);
            }

            // Create temporary copy of the boot image
            String tmpKernel = context.getCacheDir() + File.separator + "boot.img";
            File tmpKernelFile = new File(tmpKernel);
            try {
                org.apache.commons.io.FileUtils.copyFile(bootImageFile, tmpKernelFile);
            } catch (IOException e) {
                Log.e(TAG, "Failed to copy boot image to temporary file", e);
                return false;
            }

            // Run MbtoolUpdater on the boot image
            String newFile = updateMbtool(context, tmpKernel);
            if (newFile == null) {
                Log.e(TAG, "Failed to patch file!");
                return false;
            }

            // Check if original boot image was patched with loki or bump
            BootImage bi = new BootImage();
            if (!bi.load(tmpKernel)) {
                logLibMbpError(context, bi.getError());
                bi.destroy();
                return false;
            }
            int wasType = bi.wasType();
            boolean hasRomIdFile;

            CpioFile cpio = new CpioFile();
            if (!cpio.load(bi.getRamdiskImage())) {
                logLibMbpError(context, cpio.getError());
                return false;
            }
            hasRomIdFile = cpio.isExists("romid");
            cpio.destroy();

            bi.destroy();

            Log.d(TAG, "Original boot image type: " + wasType);
            Log.d(TAG, "Original boot image had /romid file in ramdisk: " + hasRomIdFile);

            // Overwrite old boot image
            try {
                tmpKernelFile.delete();
                org.apache.commons.io.FileUtils.moveFile(new File(newFile), tmpKernelFile);
            } catch (IOException e) {
                Log.e(TAG, "Failed to move " + newFile + " to " + tmpKernelFile, e);
                return false;
            }

            // Make changes to the boot image if necessary
            if (wasType == Type.LOKI || !hasRomIdFile) {
                bi = new BootImage();
                cpio = new CpioFile();

                try {
                    if (!bi.load(tmpKernel)) {
                        logLibMbpError(context, bi.getError());
                        return false;
                    }

                    if (wasType == Type.LOKI) {
                        Log.d(TAG, "Will reapply loki to boot image");
                        bi.setTargetType(Type.LOKI);

                        File aboot = new File(context.getCacheDir() + File.separator + "aboot.img");

                        MbtoolSocket socket = MbtoolSocket.getInstance();

                        // Copy aboot partition to the temporary file
                        if (!socket.copy(context, ABOOT_PARTITION, aboot.getPath())
                                || !socket.chmod(context, aboot.getPath(), 0644)) {
                            Log.e(TAG, "Failed to copy aboot partition to temporary file");
                            return false;
                        }

                        byte[] abootImage = org.apache.commons.io.FileUtils.readFileToByteArray(aboot);
                        bi.setAbootImage(abootImage);

                        aboot.delete();
                    }
                    if (!hasRomIdFile) {
                        if (!cpio.load(bi.getRamdiskImage())) {
                            logLibMbpError(context, cpio.getError());
                            return false;
                        }
                        cpio.remove("romid");
                        if (!cpio.addFile(romInfo.getId().getBytes(Charset.forName("UTF-8")), "romid", 0644)) {
                            logLibMbpError(context, cpio.getError());
                            return false;
                        }
                        bi.setRamdiskImage(cpio.createData());
                    }

                    if (!bi.createFile(tmpKernel)) {
                        logLibMbpError(context, bi.getError());
                        return false;
                    }
                } catch (IOException e) {
                    Log.e(TAG, "Failed to make changes to boot image", e);
                    return false;
                } finally {
                    bi.destroy();
                    cpio.destroy();
                }
            }

            try {
                org.apache.commons.io.FileUtils.copyFile(tmpKernelFile, bootImageFile);
            } catch (IOException e) {
                Log.e(TAG, "Failed to copy " + tmpKernelFile + " to " + bootImageFile, e);
                return false;
            }

            tmpKernelFile.delete();

            try {
                SwitchRomResult result = MbtoolSocket.getInstance().chooseRom(context, romInfo.getId(), true);
                if (result != SwitchRomResult.SUCCEEDED) {
                    Log.e(TAG, "Failed to reflash boot image");
                    return false;
                }
            } catch (IOException e) {
                Log.e(TAG, "mbtool communication error", e);
                return false;
            }

            Log.v(TAG, "Successfully updated ramdisk!");

            return true;
        } finally {
            // Save whatever is in the logcat buffer to /sdcard/MultiBoot/ramdisk-update.log
            LogUtils.dump("ramdisk-update.log");
        }
    }
}