1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

MIUI PATCHROM TUTORIJAL ZA PORTOVANJE

Discussion in 'DEV & TRANSLATION GENERAL / RAZVOJNE & PREVODILAČKE OSNOVE' started by BalcanGSM, Mar 26, 2014.

  1. BalcanGSM

    BalcanGSM Founder

    VELIKO HVALA MIUI EN ADMINISTRATORU @jack_white Za Kreiranje Ovog Tutorijala I Prevod Sa Kineskog Jezika

    Orginalni Članak : http://en.miui.com/thread-9630-1-1.html

    Introduction
    Patchrom is an open-source project initiated and maintained a team of developers at MIUI. It mainly utilizes the assembler/disassembler technology to craft a MIUI ROM for an existing ROM. Although this project is for MIUI ROM, the technology and tools are for crafting any android ROM.

    Chapter one: Setting up a build environment

    Before you get your hands dirty with MIUI, you need to set up a build environment. Everything we cover here does not require you to have the source code (if you are interested in the source code please see http://source.android.com). We recommend that you download Android's source code if you're interested in development: it isn't necessary, but it's helpful.

    1. Operating system: Ubuntu 10 or higher

    You can use Windows, Linux or OSX to build MIUI ROM (or any other ROM for that matter). However, we developed the patchrom project using Linux (Ubuntu), we recommend that you use Ubuntu 10 or above. At the moment, we have no plans to develop a patchrom for Windows or OSX.

    2. Install the Android SDK

    This section will walk you through how to install the Android SDK in Ubuntu.

    2.1 Install the Java Development Kit (JDK)

    Download the Java Development Kit (JDK) at http://www.oracle.com/technetwor ... ownloads/index.html

    We recommend using version Java SE 6 Update 38.

    Ok, now install what you've downloaded:


    sudo chmod 755 jdk-6u38-linux-x64.bin
    sudo -s ./jdk-6u38-linux-x64.bin /opt

    Next, edit the bash file (.bashrc) under your root directory (home), to port all environment PATH variables



    vim ~/.bashrc


    at the end of the file add:


    # set java environment
    JAVA_HOME=/opt/jdk1.6.0_38
    export JRE_HOME=${JAVA_HOME}/jre
    export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
    export PATH=${JAVA_HOME}/bin:$PATH

    Next, apply the changes you just made:



    .~/.bashrc


    Finally, make sure that you've succesfully installed the JDK:



    java -version


    If everything has worked, you should see:
    [​IMG]


    2.2 Download the Android SDK
    Get the Android SDK at http://dl.google.com/android/android-sdk_r21.0.1-linux.tgz
    Unzip the contents to your root directory (home). Contents should be located @ /home/patcher/android-sdk-linux

    Ok, now edit the .bashrc file in your root directory (home), change the PATH environment variable to: export PATH=~/android-sdk-linux/platform-tools:~/android-sdk-linux/tools:$PATH

    Now apply the changes you've made to the PATH environment variable:



    .~/.bashrc


    2.3 Install the Android SDK

    Launch the Android SDK Manager:



    android


    After the installation is finished you'll see following window:
    [​IMG]
    Select Android SDK Tools and the Android SDK Platform-tool and click "Install packages", then follow the installer's instructions to complete the installation.

    NB: At http://developer.android.com/sdk/installing.html, you may see that they tell you that you need to install Eclipse, however building the MIUI ROM doesn't require Eclipse, this is only required for Android development.

    2.4 Android Debug Bridge (adb)

    The most important tool in the Android SDK is adb and aapt. In the process of debugging, the command "adb logcat" comes in handy, as it prints a log for your connected device.

    To check and see if everything is working correctly, grab your device and go to Settings > Developer options, and make sure that USB debugging is enabled.
    Next, connect your device to the computer via USB and (in the Ubuntu Shell):



    adb devices


    If you see something like:

    Bus 002 Device 001:ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 001 Device 098:ID 04e8:685e Samsung Electronics Co.,Ltd

    Then congratulations! adb has recognized your device.

    NB: If you run into the message "No such permissions", you can run adb with ROOT permission (i.e. root your device). Or you can:

    1. (In terminal) Run:



    lsusb


    For the device I'm using, the output display is:

    Bus 002 Device 001:ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 001 Device 098:ID 04e8:685e Samsung Electronics Co.,Ltd

    Now copy the corresponding "04e8:685e" number (this contains the vendor id and product id). If you're not sure which line is your phone, then run the $ lsusb before connecting your device

    2. Under the directory "/etc/udev/rules.d"



    mkdir 99-android.rules


    then make the following edits: SUBSYSTEMS=”usb”, ATTRS{idVendor}=”04e8”,ATTRS{idProduct}=”685e”,
    MODE=”0666” , OWNER=”current_user”

    3. In terminal run:



    sudo restart udev


    Then reconnect your device.

    3. Sync MIUI code

    Under your root directory (home) make a new file:



    mkdir patchrom


    Install repo



    mkdir ~/bin
    vim ~/.bashrc
    set PATH=~/bin:$PATH


    Ok, switch to your patchrom directory (cd patchrom):



    cd patchrom


    4. The patchrom project

    Introduction to files and functions in the patchfrom
    • android: this directory has five sub-directories. The sub-directory src has a one-to-one correspondence with the miui/src (see below). android/src is the Android source code released by Google. miui/src is all the changes that have been on top of Google's source code. framework.jar.out, android.policy.jar.out, services.jar.out, have all been changed by MIUI, and have a one-to-one correspondence with the files in google-framework.
    • build: this directory has to do with the compiler and includes all the structures for the makefiles.
    • miui: this directory has two sub-directories: system and src. The system directory contains files that have been compiled with MIUI's source code, and these files are you will build MIUI ROM.
    • tools: this directory contains all the code for the tools included in the project. You need these tools in the process of compiling.

    Next, we'll do a build of MIUI that has been ported to i9300.

    Ok under the directory /home/patcher/patchrom:



    . build/envsetup.sh


    After the command you've run has finished, the directory will create an install out (as a sub-directory). In the sub-directory you'll find the file fullota.zip (and that's the file we publish, which you can use to flash MIUI onto you're device). You can flash it out to your i9300 by booting into recovery mode.

    MIUI releases new builds every Friday (Orange Friday), below we can try the OTA update process.

    Ok let's say you're working with the fullota.zip for the build 3.1.18, ok, under the "out" directory you'll find target_files.zip. We'll rename it "last_target_files.zip". Then, on 3.1.25, we issue a new fullota. When we issue a new OTA, in the "out" directory we now have "last_target_files.zip" and "target_files.zip", we rely on these two files to carry out an OTA. Just remember that you need to rename the target_files from the last OTA, otherwise the new fullota will replace them, and then you can't carry out an OTA.

    Under the directory /home/patcher/patchrom



    ./tools/releasetools/ota_from_target_files -k ../build/security/testkey -i last_target_files.zip
    out/target_files.zip ota_upate.zip


    -k stands for key

    -i designates the previous target_files

    out/target_files.zip: are the new target_files

    ota_update.zip: this the name of the newly created OTA file




    Chapter Two: Getting to know your Android phone

    When you get a new phone, you put in the battery, connect it to a charger, and turn it on. What happens from the moment when you turn on your phone to when you reach the Home screen of your OS? We'll answer that question by starting with a diagram of your phone's partitions:

    [​IMG]
    NB: This image does not reflect actual the order or location of partitions in your phone. It's just food for thought...

    A ROM is kind of like your computer's hard drive, it's partitioned into a couple parts: bootloader, boot, system, etc. In a second, we'll explain what some of these partitions actually do. Flashing a ROM is basically just installing some software on to a couple partitions on your phone, like installing a new OS on your computer's hard drive.

    After you've started your phone, commands are loaded from the bootloader partition. The bootloader consists of two parts: the primary bootloader and the secondary stage bootloader. The primary bootloader handles tests for hardware and makes sure it's all functioning properly. Then it copies the secondary stage bootloader to you phone's RAM and starts running it. The secondary stage bootloader runs some more preparatory processes for hardware. It gets the size of the device's RAM and launches into boot mode. Everyone is familiar with pressing & holding the Power button and some other button to boot into recovery mode, fastboot mode, or a menu of boot modes. When we talk about the bootloader on the forum, we are often referring to the secondary stage bootloader. But we don't need to get into too many details here, we can just say that the bootloader handles code, and depending on which buttons the user uses to start the device, bootloader boots into the corresponding mode.

    recovery mode: when you enter recovery mode, the secondary stage bootloader starts from the recovery partition of your device. The recovery partition is a separate Linux system. When the Linux kernel has started, it starts a program called "init" ("init is a collection of all the programs that Linux runs on). init then starts a program called "recovery". In recovery mode, the user can delete all the data stored on the device, install a new OTA package, etc. Generally speaking, manufacturers provide a simple recovery program. The famous CWM Recovery is just a basic recovery program with a bunch features added on. If you want to use CWM Recovery you'll need to make sure that your phone's recovery partition is rewritable. The unlocked bootloader that you see on the forum, refers to unlocked recovery or fastboot, and allows for the recovery partition to be rewritten. MIUI also has a recovery mode, which shares the same design principles as the ROM and can been operated using your phone's touch screen. Recovery's source code can be found and downloaded on github. We're working on a tutorial of recovery as fast as we can.

    In addition to common CPU, your phone also has a MODEM processor. This processor handles all the more traditional communication functions of your phone (for example the Radio app is written in the modem partition).

    2. Regular boot

    Most often, we power on our phones by touching the Power button (and enter a normal boot mode). The secondary stage bootloader will start from your phone's boot partition. The format of the boot partition is fixed: first there's the head, then there's the Linux kernel, and finally there's the ramdisk used with root systemfiles.

    After the Linux kernel has started, the init program in the system files begins and starts reading the script files (init.rc and init.xxx.rc). There is a lot of material online regarding the format of the script files. When migrating to MIUI, we don't make any changes to the boot partition, because on some devices the boot partition is read-only.

    In the root systemfiles, there is a very important file called "default.prop", the contents of this file are usually as follows:


    #
    #ADDITIONAL_DEFAULT_PROPERTIES
    #ro.secure=1
    ro.allow.mock.location=1
    ro=debuggable=0
    persist.service.adb.enable=1


    Every line in this file corresponds to properties of different attributes, in the following chapter we will discuss some of these properties. For now, you need to take note of two properties: ro.secure and ro.debuggable. If ro.secure=0, then you can execute the $ adb root command (this is the core ROOT). When most people talk about ROOT permission, they are referring to permissions manager program on a device (Superuser.apk) which allows them to gain ROOT permissions.

    init reads and runs the scripts, a part of the script files run files that are stored on the system partition. Next, we'll take a look at the structure of the system partition.


    3. The system partition

    Before we get started on the system partition, let's take a look at this diagram of the Android system.

    [​IMG]

    • Core-app level: This level includes all the "built-in" apps in MIUI, like Contacts, Phone, Music, etc. App developers generally deal with this level and everything above.

    • System framework: This is the core of Android, it provides the entire mechanism for the operation of Android (e.g. managing windows, apks and install files) and other things that developers deal with activity, service, broadcast, etc.

    • JNI level: Java programs and the underlying OS both depend on this mechanism, it allows Java byte-code to be transferred using C/C++ to access the underlying OS's APIs.

    • Davlik virtual machine: Android is based on Java, Android's Java code is compiled in a virtual Davlik machine, and then the virtual machine analyzes and runs the code.

    • Local libraries: Local libraries are usually developed using C/C++, and are directly compiled into the corresponding CPU, this includes the standard C library, and the skia library which is used for rendering graphics, the Browser's core webkit and engine.

    HAL: HAL stands for Hardware Abstraction Layer. In order to get all the hardware from different manufacturers to work together, Android defines a hardware interface. For example, in order to use the camera, camera manufacturers must provide a hardware interface for the device, this allows code upstream to work with different kinds of hardware.

    Manufacturers' adaptation layer: Originally Android defined HAL as a layer which would deal directly with the drivers for hardware from various manufacturers, however manufacturers were not keen on making all of HAL open source, so many manufactures provide their own "adaptation layer". The hardware interface in the HAL layer uses simple functions from the Manufacturers' adaptation layer.

    Kernel: This layer is the Linux kernel, which includes a variety of hardware drivers, contents vary between manufacturer. The Linux kernel supports all the drivers. It allows users to dynamically install and uninstall drivers. But at the moment, besides providing the drivers for Wi-Fi, manufacturers keep all of the other drivers for hardware bundled together with the kernel (out of users' reach).

    Besides the kernel (which is stored in the boot partition), all other code is stored in the system partition. Below we discuss the directories located in the system partition.

    • system/app: Core apps are stored in this directory (also referred to as "Built-in apps"). These apps cannot be deleted as easily like downloaded apps, many people ROOT their devices and the use RE file manager to get rid of bloatware masquerading as build-in apps.

    • system/lib: This directory is home to the JNI level, the virtual Dalvik machine, Local libraries, HAL, the manufacturers' adaptation layer, and the dynamic links libraries (files ending in .so).

    • system/framework: The frame's JAR package is located here. For the purposes of porting MIUI, there are three important JAR packages (framework.jar, android.policy.jar, services.jar). We'll get into each of these packages in a bit.

    • system/fonts: The directory houses the system's default font files

    • system/media: This directory holds all sorts of media files that are used by the system (e.g. boot animation, wallpapers, etc.). The grouping of these files may vary between devices.

    • system/bin: This directory holds some extensions' executable files. Generally they are written using C/C++.

    • system/xbin: Many extensions' executable files are stored here, so this directory can be empty. The popular app Busybox is stored in this directory. All the symbolic link commands established by Busybox are stored in this directory.

    • system/build.prop: This directory has the same format as the default.prop file in system files, they are both referred to as attribute configuration files. The have some defined property values, codes can read or change these property values. The property value naming convention is as follows:

    If the property value begins with "ro" it means that it's read-only, and can't be edited with code.

    If it begins with "persist", it means that the values of these properties will be saved in a file, so they will be preserved even after a reboot.

    Properties with other beginnings can be edited with code, but will not be saved upon reboot.

    Most romers will edit the build.prop file, inside there are a few ro.build properties which have to do with your phone's settings. By changing the build.prop file you can make your own imprint.

    • system/etc: This directory has some config files (not the same as the property config files). The config files in this directory don't follow any conventions. Generally speaking, script files, like the config files for GPS (gps.conf) and APN (apns-conf.xml) are located in this directory. For example, the files for special filters and effects used by HTC's camera are stored here.
    4. Data and cache partitions

    After you power on your phone and get to the Home screen, you'll probably go download some apps. All of these apps are stored in data/app. All of the data generated by Android's apps is saved in the directory "data/data". When you're "wiping data", you're really just formatting the data partition of this drive. When you do this, all the data for your downloaded apps is deleted.

    As its name implies, the cache partition houses files: for example temporary files downloaded by the Music app or the Download app.

    5. Summary

    In this chapter we covered the basic structure of Android's software and the content in important partitions, and we also briefly covered your smartphone's boot process. This knowledge will help you gain a more comprehensive understanding of the porting process.



    Chapter Three: Looking for a suitable stock ROM

    If you want to learn how to fight, first learn how to get hit . If you want to learn how to build a custom ROM, first learn how to flash your phone. First go to some of the major forums and look for a tutorial on how to flash ROMs on your phone. We really like http://forum.xda-developers.com. You can probably find what you need over there!

    In this chapter we discuss flashing your phone, some tools you'll use, and the flashing process.

    1.2 A suitable stock ROM

    First you need to be comfortable with flashing different ROMs on to your phone. After you've done this with a couple of different ROMs, we'll start looking for a suitable stock ROM. Generally speaking, stock ROMs are pretty stable. It's best if you can find a version of a stock ROM that has been rooted and deodexed.

    How can I tell if a stock ROM is suitable?

    First, you need to make sure that the version is compatable, we're trying to port MIUI based on a stock ROM. Currently MIUI V4 is based on Android 4.0.4. The changes from Android 4.0.1 to Android 4.0.4 weren't that big, so any stock ROM based on 4.0.1 to 4.0.4 is fine.

    Next you need to see if the ROM that you installed has ROOT permission. There are two types of ROOT permission:

    1. root - device: this kind of root permission appears in the form of a "permissions manager" app which can be installed on to your phone
    2. root - kernel: this kind of root permission appears in the form of a command in adb:
    With your device connected, in Ubuntu's shell enter:



    adb root
    adb remount


    If you are able to run these commands successfully that means that the kernel has been rooted. If you enter



    adb shell


    the phones shell will be preceded by a "#"

    If both commands failed, when you run $ adb shell, you'll see that the phone's shell is still preceded by a "$". If you run the su command, the device will produce a popup asking you whether or not to grant root permission, this indicates that a "permission manager" app has been installed on the device. After you run su the command, the device's shell will be preceded by a "#".

    In the following chapter we'll look at the key places that we need to change in the system partition in order to port MIUI. Either type of root can make the device's system partition read/write, but a kernel root is more convenient, so we recommend that you use a ROM whose kernel has been rooted.

    The patchrom program provides tools and scripts that require your device have root (kernel) permission, if you have root - device permission, that's ok too, but you'll need to change the scripts a little bit. If you only root - device permission, the command $ adb remount will fail. Then you need remount the system partition and change the permissions in the directory, in order to change the contents of the system partition. You also need to alter a couple of the scripts that we provide you with. (After this point we won't differentiate between the two types of root, because we assume you'll know how to change the system partition).

    Finally, check to see that the ROM that you've selected can be flashed in Recovery mode, it doesn't have to be CWM Recovery, if it has the ability to wipe data/cache and install the zip package, that's all you need (but we still think CWM is the best). Within regards to every device, if you want to create a MIUI ROM package automatically, we require that every device provides a package in zip format, this package can be installed in Recovery mode. Don't worry if you can't find a zip package that you can install in Recovery mode, below we'll get into how to get a package that meets zip standards.

    First, we have a tool called mi that's located in the patchfrom directory on your computer:



    . build/envsetup.sh
    mkdir mi
    cd mi


    Now connect your device to the computer, and make sure that USB debugging is enabled:



    adb reboot recovery
    .../tools/ota_target_from_phone -r


    1. (or reboot into Recovery mode manually via button pressing)
    2. (The -r means that you're using this tool in Recovery mode, but you can also use these tools in regular mode)

    1.3 adb logcat

    In the first chapter, we mentioned that adb was a really important command, especially because in the process of porting, the command we most often use is adb logcat. By using this command you can print detailed log info.

    Every line's format:


    I/ActivityManager( 585):Starting activity:Intent{action=android.intent.action..}


    The first letter in the expresses info type (E = Error, W = Warning, I = Normal Info)

    The Activity manager (after the first forward slash) is an information tag, normal tags provide corresponding information about the apps and programs.

    You can view only the tag info by entering:



    adb logcat tag:* *:S


    The number in the parenthesis is the progress id number (pid)

    The words after the colon offer a more detailed explanation, when you run into a problem, look here to get detailed information about the bug.

    When you are porting the command



    adb logcat*:E


    comes in handy! As it enables you to view error data only.

    learn more about adb here: http://developer.android.com/guide/developing/tools/adb.html

    After you've chosen a ROM, we can guarantee that when you first start your phone, running the command adb logcat will enable you to see log info. If logcat only starts to print info once you've reached the Home screen (or doesn't print any info at all), it's going to be hard to port. If you're only going to change some pictures, then that's ok, but if your trying to port MIUI, we require that the device you're trying to port enables adb logcat to print information as soon as you turn it on.

    2. Altering boot.img

    In Chapter two we briefly discussed the key part of having a root - kernel was the values of the properties in System File default.prop, ro.secure and ro.debuggable. System files and the kernel are both located in the boot partition. If you can change this file in the boot partition, than you get root - kernel permission.

    Next we'll explain a bit how to get a root kernel. Generally speaking, every device's install package contains a boot.img file. This file is the boot partition's image file, when you install the package, this file is used to write the boot partition. The boot.img provided by Google has a standardized format, if you're going to keep with the format, you can use the method below to change the file. But if you're not going to keep with Google's format, you need to go to the forums to understand how to change the boot image. Generally, if there's a file in the install package called boot.img it's best to stay with Google's format. If there's not, then don't, and head over to XDA. For example, Samsung's i9100's install package contains a gile name zImage (you can find a tutorial of how to change the zImage on XDA).

    Ok, under the patchrom directory, and there is a boot.img file, execute the following command:



    ./tools/unpackbootimg -i boot.img


    the output should look something like:


    BOARD_KERNEL_CMDLINE console=ttyDCC0 androidboot.hardware=xxx
    BOARD_KERNEL_BASE 00200000
    BOARD_PAGE_SIZE 4096


    If it looks all crazy, than it's safe to say that the boot.img does not follow a standard format. Copy down the output here because we're going to need it in a second. Under the patchrom directory you'll also see boot.img-ramdisk.gz, this file is a compression of the root file system. And there's also a boot.img-kernel file, which is a Linux file.



    mkdir ramdisk
    cd ramdisk
    gzip -dc ../boot.img-ramdisk.gz | cpio -i


    After you've run the three commands above, the ramdisk directory acts as the root file system after the phone has been started, you can use any editor to change the default.prop file.

    Ok, now repackage the ramdisk directory:



    cd ..
    ./tools/mkbootfs ./ramdisk | gzip > ramdisk-new.gz


    Now, to make a new boot image, run the command below:



    ./tools/mkbootimg --cmdline ‘console=ttyDCC0 androidboot.hardware=xxx’--kernel boot.img-kernel --ramdisk ramdisk-new.gz --base 0x00200000 --pagesize4096 -o boot-new.img


    In the command line above:
    --cmdline: this was printed before as the BOARD_KERNEL_CMDLINE
    --kernel: Linux kernel file
    --ramdisk:this is the compression of the root system file
    --base: this was printed before as BOARD_KERNEL_BASE
    --pagesize: this was printed before as BOARD_PAGE_SIZE
    -o: This is the name of the output file

    3. deodex

    After we flash the ROM we've selected on to the device we've chosen, we need to deodex.

    You only need to understand that an odex is a file that has been optimized. Odex files are interdependent, and we are just going to change one file. So we need to deodex, which means turn a odex file into a dex file, which, in turn, will enable us to change these files separately.

    Generally speaking, when stock ROMs are released they are all released in odex format. How can you tell if your ROM is in Odex format? Run the command:



    adb shell ls /system/framework


    If you see an .odex at the end of the file, then the ROM's is in odex format. You can use the tools in the patchrom to deodex the file. You can find this tool in patchrom/tools. It's a script called deodex.sh.

    4. Makefile

    Above we already discussed how to get a suitable install package, now we need a make file to get started. Below is the most basic patch rom:

    [​IMG]

    Below is brief description of each file:
    local-zip-file: This is the install package for the suitable ROM you found, this is a required for every device
    local-out-zip-file: after you run "make zipfile" this outputs the name of the ROM
    local-miui-modified-apps: In patchrom/build/miuiapps.mk, there's a list of all of MIUI's built-in apps, these variables define which apps are MIUI apps that we have changed.
    local-modified-apps: These variables define which apps have been changed in the local zip file
    local-miui-removed-apps: Often we don't want to include all of MIUI's apps in the port (because some of them don't work with non-Xiaomi-phone hardware... like the Camera app), these variables define which apps we don't want to inlcude
    local-phone-apps: This defines the apps which we want to delete from the local-zip-file. We have written a blocklist for MIUI apps (above) and written a exceptions list for the apps in the stock rom. Together the lists define what we want to block from MIUI and what apps we need to leave included in the stock rom.
    local-zip-misc: The contents of this directory vary with the type of device that you're using
     
  2. BalcanGSM

    BalcanGSM Founder

    Chapter Four: Decompiling

    If you want to change the built-in apps in an OS and its code, when you don't have its source code, you have to decompile it to make changes.

    Like a lot of other tutorials, we're going to start with a "Hello world!" example: HelloActvity.apk. When you install a this APK on to your phone it will display "Hello,World!" on your Home screen.

    1. Decompiling

    In the patchrom directory:

    ./tools/apktool d HelloActivity.apk

    After you've run this command, a new directory called HelloActivity will be created in the current directory.

    The file structure should look like this:

    [​IMG]

    The apktool.yml port file is created by tThe apktool.yml port file is created by the apktool, you don't need to change this file. Ok, now we're going to talk about the AndroidManifest.xml, res, and smali files in the HelloActivity directory.

    2. AndroidManifest.xml

    If you want to understand this file, you have to be very clear on inner-workings of the Android system. Luckily, when we change an APK we don't need to change this file. This guide will just help you to gain a general understanding.

    Android install packages are generally referred to as "apk" (which is an abbreviation for Android Package). Generally, apps will have one or several "Activities". What is an "Activity"? In theory they are an interactive window visible to the user. When you use Android everyday you are pretty much always interacting with activities (every interface is an activity). Androidmanifest.xml is a simple xml-format list: it's like at the grocery store and you get a receipt that lists the items that you've purchased. AndroidManifest.xml serves the same purpose, it tells the system what activities it has. (ok, it's actually more complicated than that, and if you want to learn to develop for Android check out this article: http://developer.android.com/guide/index.html).

    Ok in the AndroidManifest.xml file under HelloActivity, you can see the following content:

    [​IMG]

    See the line , this includes the Activity that will display the text on your Home screen, or this Activity can also be started via the icons displayed on your Home screen. You'll also notice the second line: android:label=”@string/app_name” and also android:icon=”@drawable/ic_launcher_hello”. These two properties do the following: android:label shows expresses the name that will apear on the Home screen, and android:icon expressions the icon that will be displayed. If you want to change the name or the icon that will be displayed on your Home screen then you just change the corresponding resources, which we'll get into right now...

    3. Resources

    Under the directory res (short for resources), are all the resources the app needs. What are resources? Generally speaking, resources are elements that are used in the GUI (graphic user interface) (like images, texts colors and sizes etc, also borders and interface layouts). An important characteristic about "res" is the separation from the display on the user interface and the logic of the code. When you need to replace an image or need to make a simple change to a user interface, you don't need to change the code. Android apps will put all the resources that they use in the res directory. The structure/content of the directory looks like this:

    [​IMG]

    For HelloActivity, the res directory has three sub-directories: drawable-hdpi, layout, and values. Because HelloActivity is relatively simple the content in pretty sparse. But for more complicated processes items in the res directory are relatively more, but the basic principles are the same.

    The subdirectories under res are organized according to the type of resources that each contains. The resources that begin with "drawable" mean that they are graphics, you can see drawable-xhdpi,drawable-hdpi,drawable-mdpi,drawable-ldpi, these xhdpi,hdpi,mdpi,ldpi represent different resolutions. Screens with different resolutions will use different graphics. If you want to change some images, directly alter these files to do it. It's a little but complicated to change out images and it's best if you make sure that the images you use are compatible (also consider color scheme, size, and nine patch issues).

    Files that begin with layout have to do with layout (suprise!). anim sub-directories contain resource that are used for animations, files that being with xml are contain things used by other .xml files.

    directories that begin with "values" contain what we "basic elements", for example colors.xml (dictates colors), dimens (dictates dimensions), and strings deal with the text that is displayed. The strings for HelloActivity should appear as follows:

    [​IMG]

    The part of the sting that begins with endsWith(Ljava/lang/String;)Z
    move-result v15

    if-eqt v15,:cond_6


    You can see that the code is determining whether or not the string "v9" ends with ".xml". If it does not end in .xml it moves to :cond_6. Ok, let's go to the i9100 to find the corresponding code. In this example, we can use "xml" as the keyword to run a search in the i9100's loadDrawable method. We find the following:


    const-string v17,”.xml”
    move-object v0,v10
    move-object/from16 v1,v17
    invoke-virtual{v0,v1},Ljava/lang/String;->endsWith(Ljava/lang/String;)Z
    move-result v17
    if-eqz v17,:cond_b


    The logic of this block of code and the one we found in MIUI is the same. We can see the code that MIUI inserted should be placed after cond_b. After you find cond_b in the i9100 codes, we'll take a look at the codes that follow this condition. You'll realize the code we inserted and the code following the condition are similar, the code below confirms that we should put the code added by MIUI after cond_b.

    Let's look at the output again, the code inserted by miui has two outputs (it's a conditional)

    if-nez v6,:cond_1

    If the space beneath v6 is not empty, then it jumps to :cond_1. Let's take look at what cond_1 does exactly. The code looks like this:


    :cond_1
    :goto_1
    if-eqz v6,:cond_2
    move-object/from16 v0,p1iget v0,v0,Landroid/util/TypedValue;->changingConfigurations:I


    In the i9100 we find a similar block of code:


    :cond_1
    :goto_1
    if-eqz v7,:cond_2
    move-object/from16 v0,p1
    iget v0,v0,Landroid/util/TypedValue;->changingConfigurations:I


    The only difference is v6 has been changed to v7, this explains that the code is checking v7's value, so we need to change the code we inserted as well:

    invoke-virtual/range{p0..p2}
    Landroid/content/res/Resources;->loadOverlayDrawable(Landroid/util/TypedValue;I)Landroid
    /graphics/drawable/Drawable;
    move-result-object v7
    if-nez v7,:cond_1


    4.5 Logic

    This situation usually has to do with inner classes, we you realize that there aren't many changes to the source code, but the changes in the decompiled smali code are big.

    For every java file's inner class, a single stand alone smali file is created. For example, AcitvityThread$1.smali, these file's naming convention is anonymous, it's the external class + $ + digital. Or it's the external class + $ + the name of the internal class.

    When the internal class calls on an external class's private methods, the compiler will automatically create a static function. For example the type below:
    [​IMG]

    In the internal class A's func methods we call on the external class setup method. In the end, the compiled smali code appears as the following block of code in the Hello$A.smali file:
    [​IMG]
    Here's the block of the Hello.smali code
    [​IMG]

    We can see the that the compiler will automatically generate an access$000 method. If we were to insert a call for an outer class's private method into a comparatively complicated inner class type, it would only lead to the synthesis of a new method, but the names of these new syntheses might also be different, it turn, the smali files would be even more different.

    For example, in the file KeyguardViewMediator.java, at the end of the definition mBroadcastReceiver we add a single line of code "adjustStatusBarLocked()", but the smali that's created in the end has even more differences. This because of the compiler's call on this private method, even though it just leads to the synthesis of a new method, but the names for these new methods are all over the place. In these circumstances, we don't have to make big changes to the code, we can just create a name that doesn't conflict for this and other private methods. For the exact method refer to the changes in the i9100's android.policy.jar.out file.

    5. Injecting smali code

    5.1 Confirm that you need to inject smali code

    First you need to confirm that you need to inject smali code using comparison tools and methods (we discussed them above and won't go into them again here). In the screen shot below the area highlighted in red needs to be injected with smali code.
    [​IMG]

    5.2 Confirm injection target

    This part looks easy, but it's actually pretty hard. This is mainly because there are many injection targets that are hard to confirm, and need to be tried again and again.

    After you use the APKTOOL to decompile the APK and JAR packages that you want to inject, first confirm which smali file you need to inject. This is mainly for java files that contain anonymous inner classes. For example when porting changes to the file PhoneWindowManager.java, after you decompile the file there will be many different smali files (PhoneWindowManager$1.smali,PhoneWindowManager$2.smali). These files have anonymous inner class smali code (i.e. they don't have names after they have been compiled we can only use $XXX to distinguish them).

    If the smali code you injected is from honeWindowManager$5.smali, generally, you can't inject it directly into the device directory, because different devices inner anonymous classes are all in different sequences, they are executed differently, and the smali files themselves are executed differently. Generally, it's better to find a couple of smali codes closer to PhoneWindowManager$5.smali, and look at the other function calls and functions name and class hierarchies. Are the relationships similar to the target file you're going to inject into?

    Of course, for java files without anonymous inner classes you can directly inject the corresponding smali files.

    After you confirm the file that you are going to inject, you need to take another step and confirm the the area into which you're going to inject code. Because none of the variable types in smali code are fixed, in addition to the optimization from the compiler, different ROM's APKs and JARs look VERY different after they have been decompiled. But this doesn't really affect what we're trying to do. We are focusing on smali code's actions - the sequence of the called functions, order, member variables, in order to confirm the target injection area. Also, you can be a little more lenient with areas containing newly added smali code, new variables are declared outright at the end of the file, newly added commands are also added directly at the end of the file. In a nutshell, this process doesn't require a lot of experience per se, it just requires you try multiple times over a period to gain a "feel" of where you should inject the code.

    At last, the example described above is pictured below:
    [​IMG]

    In the image above much of the red isn't the same, the code included in the blue box is the smali code that we've decided to inject. Through matching via the context, the area outlined by the green box is the target area for the smali code. Even though above and below have many variable and commands that are not the same, but this doesn't really effect what we're trying to do.

    5.3 Injecting the code

    First, inject the smali code into the corresponding target area. Next, we need to "localize" the code we've injected -- change some variables, labels, logic, so that they match the Smali code that you are trying to port. Of course, if things are really complicated, you may need to rewrite the smali code or rewrite the java code from scratch to complete the injection. Let's continue with the same example from above.

    [​IMG]

    The code in the blue box in the picture above is the code that we've injected. We can see the variables we've changed: move-result-objectv2 and invoke-virtual{v2,v0,v1,v15},Lmiui/net/FirewallManager;->onStartUsingNetworkFeature(III)V. This is because invoke-virtual{v2,v0,v1,v15},Lmiui/net/FirewallManager;->onStartUsingNetworkFeature(III)V in the new smali code v15 has other uses. We need to find an unrelated context variable call to complete the variable transmission. So, we'll change "move-result-objectv15" to "move-result-objectv2". And change the onStartUsingNetworkFeature() call parameter list.

    Also, in the code we moved, there are some special things that have to do with resource ID. Let's look at the example below:

    [​IMG]

    Now we need to move everything in the blue box to the space outlined by the green box, however const v6, 0x10403c1 (in the middle of the green box) prevents us from doing this. We can't just crudely cut the contents of the blue box and paste them into the green box. If we do that, a runtime error will occur when the res code can't find the files it needs. We need to use the original files from the decompiled ROM's framework-res.apk and the target ROM's framework-res.apk. Using the 0x10403c1 ID we can find the name of the corresponding resource in ROMframework-res.apk. Then using the resource's name we find the target resource in the target ROM's framework-res.apk. After that, just switch in the ID of the resource in the target ROM. When you're done with everything, the code should look like this:

    [​IMG]

    The resources that begin with 0x1 are all framework-res.apk resources, 0x2 are generally the manufacturer's resources, for example: moto-res.apk or com.htc.resources.apk. MIUI's resources all begin with 0x6, are are located in framework-miui-res.apk.

    5.4 Assembling smali code

    Assembling smali code is pretty straight forward. Use apktool b XXX XXX.apk to assemble the smali code as an apk or jar package. But if you run into an error, the apktool provides you with very little information about the error. So little in fact that we can only manually check which smali files had port errors.

    Here, we'll summarize some problems you may run in to when porting smali code.

    ->The invoke-virtual command's parameters can only use v0~v15, if you use a variable that is over v15 an error will occur.

    There are two ways to fix this problem:
    A. use the "invoke-virtual/range {p1 .. p1}" command, but here request that the variable name is linked.
    B. add a "move-object/from16 v0, v18" variable, to change the variable name (make it less than or equal to v15).

    The command call p0 is equal to the value of the usable variables +1, pN is equal to the value of the usable variables +N. For example the value for the command .local is 16, which means that the values for the usable variables are v0~v15,t then p0 equals v16, and p1 is equal to v17. For example in the screen shot below, the codes in the blue box cannot be assembled. After we find that the command .local value is 33, so p0 is equal to v33, thus it can't be compiled until you change it (see the code in the green box).

    [​IMG]

    ->Jump labels overlap. Here we're talking about two case labels, for example cond_11, leads to a build break (i.e. it can't be assembled). The way to fix this is to change the conflicting labels and the associated jump commands. Really it doesn't matter what you call these labels (you could even call one ABCD_XXX) just so long as it can work with the corresponding goto command.

    ->Using an undefined variable. How many variables every command can use is contained in a sentence noted by the phrase ".local" in the command. For example, .local30 shows that this command can use v0~v29, if you use the value v30 there will be a build break.

    5.5 Adjusting smali code

    The most im-porntant part of adjusting smali code is to resolve the runtime errors generated by the code the you injected. More specifically, you need to get the smali code that you injected to go through the dalvik virtual machine's bytecode verifier. It's easy to get a hold of where the error occurs, just enter the two commands:



    adb logcat | grep dalvikvm
    adb logcat | grep VFY

    The VFY info will produce the smali code files which contain errors, commands, and reasons for the errors. The dalvikvm info can provide you with a call stack and the context for the process.

    5.6 Finding and adjusting smali problems

    >List of variables and function declarations are different, this is mainly occurs in the following two places:
    A: The class of variables that the command uses are not the same. By tracing the context of the variable and looking at the assigned actions you can resolve this problem.
    B: The number of variables listed for the command is less than or greater than the command's declared variables. Resolve this by comparing the command's declared variables.

    >Command call methods are incorrect
    For example: public and invoke package functions use the invoke-virtual command, private command functions use the invoke-director command. If they're used incorrectly, it will generate a runtime error. You need to adjust the related smali codes.

    >Class interface wasn't implemented. This occurs mainly because a new sub-class has been added but hasn't been implemented to the higher class interface. Just increase the space recognition to fix the problem.

    >The signature is incorrect. You confirm which package's signature is incorrect by running the command: adb logcat | grepmismatch. To resolve the problem, just rename the packages with incorrect signatures. Of course, if you have a lot of signatures that don't match you should rename all the APKs.

    >Can't find resources. This problem comes in many different flavors (i.e. it can occur in many different ways). Here are some of the most common reasons:
    A: The system resources file signatures are not accurate, which leads to the system resources not being loaded, and thus they cannot be found. To clarify, we're talking about the apk files under the directory system/framework.
    B: There's a porting error in the smali code resource ID, there's no way to find the corresponding resource in system resources.
    C: There's a problem with the related resources' ported classes, so there's no way to load the related resources.

    Also, when you're adjusting the code, you need to trace the codes execution channels, but don't have Debug, here's another simple method:

    >Add some smali log info:
    A: Change the functions ".local" variable, add two more variables on the base of the original. For example v11, v12.
    B: In the places where you need to print a log add the following smali code:
    const-string v11,”@@@@”
    const-string v12,”interceptPowerKeyDown enter”
    invoke-static{v11,v12},Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
    If the variables are added are v28 and v29, then you need to use the following statement:
    invoke-static/range{v28..v29},Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

    >Print the program call stack:
    A: Change the functions ".local" variable, add two more variables on the base of the original. For example v11, v12.
    B: In the places where you need to print the call stack add the following smali code:
    new-instance v1 Ljava/lang/Exception;
    invoke-direct{v1,Ljava/lang/Exception;->V
    invoke-virtual{v1,Ljava/lang/Exception;->printStackTrace()V

    6. Parting advice
    Finally, Here's some advice with regards to changing smali codes:
    >Be careful about where you inject smali code into the corresponding code on the device you're porting too
    >Pay attention to the changes the sequence of variables
    >Don't use the apktool to package the files you've changed, if the code insert contains errors, there won't be any way to compile it. But the error data from the apktool is illegible, and you won't be able to tell where the error occurred.
    >Don't worry if you encounter errors. Stay calm and find the source of the error, using common solutions to common problems, as we discussed above. It's not that hard to change the smali code, the more you do it, the easier it gets.
     
  3. VotaPeroiceta

    VotaPeroiceta Gold Members Member

  4. EmedgeSodsRed

    EmedgeSodsRed Member

  5. Keemeproria

    Keemeproria Member

  6. FEFENTETTYZEW

    FEFENTETTYZEW Gold Members Member

  7. Keemeproria

    Keemeproria Member

  8. FEFENTETTYZEW

    FEFENTETTYZEW Gold Members Member

  9. Keemeproria

    Keemeproria Member

  10. Garazoogs

    Garazoogs Member

  11. mefselespap

    mefselespap Member

  12. FEFENTETTYZEW

    FEFENTETTYZEW Gold Members Member

  13. platheste

    platheste Gold Members Member

  14. Isododumunrearo

    Isododumunrearo Gold Members Member

  15. platheste

    platheste Gold Members Member

  16. evorwaybearo

    evorwaybearo Member

Loading...