OS
Operating
Systems
and
Real
Time
Operating
Systems

General information


Lab on Android



The purpose of this lab session is to enter into some internal features of the Android system. The Android we are going to use is provided as a docker container already installed and configure on Eurecom Linux machines. This session is not graded, and so, you don't have to send me a report or source file, but you may do it if you wish.

If you know nothing about Android, don't panic! The lab is guided, and you will almost have no code to do in this lab: most of the time, you will just have to understand elements of Android by executing commands I provide. Sometimes, you will have to find commands in a documentation which link is provided. Thus, using Google in this lab shall not be necessary ;-)

Preparing for the lab

Using your own laptop


If you were to work on your own laptop, you first need to access to the docker container as follows. Do the following commands ONLY if necessary, e.g. on your own laptop:
$ docker pull cryptax/android-emu:2021.03
$ docker run --privileged -d -p 5022:22 -p 5900:5900 --name android-docker cryptax/android-emu:2021.03
Then, if you are in Linux, do the post-installation steps.
Last, if for some reason there is a problem with your docker machine, do as follows. First, list running containers:
$  docker ps
Find the related identifier (for instance, "47043f7938cd"), and then do a stop on it:
$ docker stop 47043f7938cd
Then remove the stopped container:
$  docker rm 47043f7938cd
And then re-run the command to start the container.

You could also try -at your own risk- to make the lab on your Android phone connected by USB to your laptop, or to simply install an Android emulator, ideally the x86 Android 11 emulator.

Using a EURECOM computer

All the lab explained below shall be doable. Yet, network commands (e.g. wget) may not work within the docker installed on the Eurecom machines. Perform these commands on your host computer, and then copy the file to the docker machine using scp.

Linux computer

The emulator might not display graphical information. But most lab questions are still doable.

Windows computer

You first need to start a terminal on a Linux eurecom machine (eurecom1 to eurecom44). To do so, start XLaunch on your Windows session: a configuration window should open. On the first tab, select "multiple windows", click on next. Then select a program to be executed (xterm), and select PuTTY as the connection mode. Enter your login and password. Select a Eurecom computer (again: eurecom1 to eurecom44), number provided by your (favorite) teacher. Click on next until the configuration window closes. You should obtain a terminal on the remote Linux computer. From this terminal, you should be able to do the lab as instructed below. Note that Only one student at a time can remotely connect to a given Linux computer (i.e., one student connects to eurecom1, one student to eurecom2, and so on).


Starting Android

The architecture of Android was presented in the introduction lecture. Basically, Android is based on a version of the Linux kernel enhanced with security features (SELinux), and a Dalvik virtual machine.
  1. Connecting to a container. The Android emulator is provided within a Linux docker container already installed on your local machine. To connect to this Linux container, do as follows (password: mypass):
  2. [Shell on your host]$ ssh -X -p 5022 root@localhost
    
    An alternative is to open a graphical session on the container using vnc. If the connection with ssh doesn't work for some reason (e.g., you are using your own docker on your Windows laptop) or if starting the emulator fails, then use vnc to connect to the docker container. You can also so this on the Eurecom PCs if you prefer to:
    [Shell on your host]$ vncviewer 127.0.0.1
    
    or depending on your Linux installation:
    [Shell on your host]$ gvncviewer 127.0.0.1
    

  3. Operating system of the container. Find a way to find the kernel and memory information installed in the container. Compare with your host machine. How do you explain this? Do you know the difference between a container and a virtual machine?

  4. Where is Android? Now, start the Android system as follows (be patient, the Android emulator may be long to show its first display):
  5. [Shell in container]$ emulator
    
    This will start the android emulator emulating a x86 processor. By the way: Find out which command is really executed in the system when executing "emulator".
    (Help me!) Have a look at the .bashrc file, or use the alias command.


    If at some point during the lab the Android emulator should be reset, and only in that case, then do as follows [Beware: all data inside the emulator will be lost]: kill your emulator processes, and then restart the emulator:
    [Shell in container]$ kill -9 ....
    [Shell in container]$ emulator -wipe-data
    
    Depending on your computer, the emulator may take quite a long time to start.

First investigations on Android

  1. Shell on the phone. At first, we will not use the graphical emulator, but we will simply connect with adb to the emulator. ADB stands for "Android Debug Bridge". It is a facility to connect with a Command Line Interface to an Android system.
  2. [Shell in container]$ adb shell
    
    You are now connected to this emulated phone. You may have to be root to execute some of the commands of the lab. To do so, in adb shell, type:
    [adb shell]$ su
    


  3. My first adb shell commands. Most adb shell commands are explained here. You are asked to:

    1. List the current users of the system. Also, find out the maximum number of users for Android?
    2. (Help me!) Use the "pm" command with the correct parameters


    3. Find to a way to verify that the emulator supports the bluetooth feature.

    4. What are the kernel debug messages? Are there any specific adb command to see the Android logs? Are there any error messages regarding the battery? Can you explain these errors?
    5. (Help me!) Use "dmesg" or "logcat"


  4. Gathering more information on the system with dumpsys. First, list the services that can be investigated with dumpsys:
  5. [adb shell]$ dumpsys -l
    

  6. The load of the CPU can be monitored with dumpsys as follows:
  7. [adb shell]$ dumpsys cpuinfo
    
    What do you observe? Is the load of the CPU high?

  8. Find how to get the battery characteristics with dumpsys. Explain what you observe.

  9. Then, find a way to investigate the two following elements:

    1. Time before the screen goes to off ("off timeout")
    2. (Help me!) "dumpsys -l" can help you find the right command


    3. Widgets currently installed in the system (i.e. visible on the display), and the ones that could be installed on the screen.

A closer look at the GNU/Linux kernel of Android

  1. Start scripts of Android. A few starting scripts executed when the system starts are located in /. The main one is called init. Basically, this script sets up I/O (e.g., USB, sor debug wwia adb), and sets the security features of SELinux, to ensure security elements are set asap when booting. It also calls other starting scripts.

  2. Tracing script. One script which is called is init.environ.rc. Look at its content, and determine its role.

  3. Tracing capabilities. Google provides a facility named atrace to monitor elements of the operating system. First, let us list the tracing capabilities of atrace:
  4. [adb shell]$ atrace --list_categories
    

  5. Analyzing events of the window manager. Activate the tracing for the window manager for 10 seconds. When the tracing is started, graphically log into the Android emulator by making a slide up from the lock with your mouse. Then, wait for the tracing to complete, and understand the trace. To do this, you will probably have to consult the manual of as follows:
  6. [adb shell]$ atrace --help
    

  7. Tracing interrupts. Trace the interrupt during 5 seconds while doing nothing in the (graphical) emulator. What is the most frequent interrupt? Redo the same but unlock the emulator screen while tracing, and click on an icon. Observe the difference i.e. find at least one interrupt that is part of the tracing only when an icon was clicked.


  8. Monitoring actions. Similarly, find a tracing categorie that is empty when doing nothing in the (graphical) emulator, and that shows actions when cliking on a icon.
  9. (Help me!) Try to find a category related to user inputs


Using the emulator and the shell

  1. Graphically log into the Android emulator. Then, come back to the shell, and type:
  2. [adb shell]$ ps
    

  3. Start the Chrome browser. Do ps again, and find the difference:
  4. [adb shell]$ ps -A
    

  5. Now, click on the "home" button (i.e. the "circle" icon) in the graphical interface on the right part of the emulator. The browser should disappear. Evaluate if the process is terminated e.g. by listing again the processes:
  6. [adb shell]$ ps
    

  7. Find an adb shell command to terminate the browser process. Before executing the terminaison action, open another "adb shell" and starts the monitoring of the kernel with logcat. Then, terminate the browser process with a command in the first shell, and then verify that the browser is really terminated.

Reversing an Android application package (apk)

  1. Getting an Android app. From a shell in the docker machine (and not in the emulator), get the "root verifier" Android app to analyze as follows. The app is downloaded from the "F-Droid" market place.
  2. [Shell in container]$ cd ~
    [Shell in container]$ mkdir myapp
    [Shell in container]$ cd  myapp
    [Shell in container]$ wget https://f-droid.org/repo/com.abcdjdj.rootverifier_12.apk
    

  3. Unpack the app
  4. To do this, you first need to install in the docker apktool. Download it as follows:
      $ wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.6.0.jar
      $ mkdir /opt/apktool
      $ mv apktool_2.6.0.jar /opt/apktool/apktool.jar
    
    [Shell in container]$ java -jar /opt/apktool/apktool.jar d com.abcdjdj.rootverifier_12.apk
    
    We have the right to unpack / analyse this application because its license authorizes this. Otherwise, that would not be permitted.
    Once you have unpacked the application, you should obtain the various elements of the application in the subdirectory named com.abcdjdj.rootverifier_12.apk. Basically, you have three elements:
    1. The manifest of the application, including its certificate, and the main information
    2. The resources. You should identify here the description of the graphical interface, as well as images used by the app
    3. The assembly code of the app, in smali format (byte code). One file corresponds to the Main activity. Open this file, and add your email among the developer emails (you are now indeed part of the developers!) in the about section.

  5. Creating a new Android app with your modifications. To do so, we now create a new valid apk package. We will use another directory in which we will put the new source code, and from which we will create the new apk. For this, you will also need the smali application, that you can find here: https://bitbucket.org/JesusFreke/smali/downloads/. Install it in /opt.
  6. [Shell in container]$ cd ~/myapp/
    [Shell in container]$ mkdir myfirstapp
    
    We make the new app also from the elements of the former app:
    [Shell in container]$ unzip -d myfirstapp com.abcdjdj.rootverifier_12.apk
    
    We now need to create a new executable file from the modified smali code, and to put the new executable at the right place. To do so, execute the folowing commands:
    [Shell in container]$ cd myfirstapp
    [Shell in container]$ java -jar /opt/smali.jar a ./smali/
    [Shell in container]$ cp out.dex ../myfirstapp/classes.dex
    
    This command should create an out.dex file, and place it in the new application under the name classes.dex. Verify that the classes.dex file really exists before going to the next stage.

  7. Generating a new apk.
  8. [Shell in container]$ cd ../myfirstapp/
    [Shell in container]$ rm -rf META-INF/
    [Shell in container]$ zip -r myfirstapp.apk *
    
    You should then test that the apk contains everything, apart from the package signature: resources, manifest and compiled classes:
    [Shell in container]$ unzip -l myfirstapp.apk
    
  9. Optimizing the apk. This is also called "alignment".
        $ [Shell in container] /opt/android-sdk/build-tools/31.0.0-rc1/zipalign -v -p 4
        myfirstapp.apk myfirstapp-aligned.apk
      
  10. Signing the application. What happens if you try and install this application on an emulator or a smartphone? Android will complain with INSTALL_PARSE_FAILED_NO_CERTIFICATES. That is because the app is not signed yet. We now need to sign the new package. We first delete the former package signature, and we create the apk:
  11.   [Shell in container]$ keytool -genkeypair -keyalg RSA -keystore mykey.jks -keysize 2048 -validity
      10000 -alias test
    
    This command should have generated the application key in a file named mykey.ks. We finally need to sign the application with the new key:
      [Shell in container]$ /opt/android-sdk/build-tools/31.0.0-rc1/apksigner sign --ks mykey.jks
      --in myfirstapp-aligned.apk --out myfirstapp-signed.apk --min-sdk-version 25
    
    The "test" at the end of the previous command means that the system tests the apk signature at the end of the signature process.

  12. Testing the app in the emulator. We can now install the new app in the emulator:
  13. [Shell in container]$ adb install myfirstapp-signed.apk
    

  14. Testing the modification. Use the graphical emulator to log into the emulator, find the app, start it, and try to find the impact of your modification...

Getting system information from an Android application

Now, you will be less guided.
  1. Get the sources of the app "AnotherMonitor" from FDroid.

  2. Find in the source code how the application gets the memory and processor informations. Once you've found this, test with "adb shell" if the way the application gathers information on memory and cpu is likely to work.

  3. Test the app from its apk (available on FDroid) in the emulator to verify if the app works.

Emulation of other system information

  1. Get the sources of the app "CpuSpy" from https://github.com/bvalosek/cpuspy. Try to basically understand the code. This (short) doc could help you understand the code.

  2. Where is the frequency value handled in the graphical interface? What happens if the considered core is in idle mode?

  3. How is the kernel version found in the application? Can you do this "by hand" in adb shell to test if their way of doing works?

  4. Where are the states of the processor stored in the android file system? Does this file exist in the emulator? So, do you think the application can work in the emulator?

  5. Test the app in the emulator ... you could also test on your own (Android) device to see what happens... What can you conclude on the emulator?

(bonus work) Native code execution in Android

  1. At first, find the processor model emulated in your Android system

  2. Install the compilation environment ndk in the docker image. To do so, proceed as follows:
    • Put the ndk environment in the container:
    • [Shell in container]$ cd /opt
      [Shell in container]$ wget https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip
      [Shell in container]$ unzip android-ndk-r13b-linux-x86_64.zip
      
    • Now, we need to create the toolchain - including the cross-compiler - for the emulated processor (this process might be a bit long):
    • [Shell in container]$ cd /opt
      [Shell in container]$ cd android-ndk-r13b
      [Shell in container]$ ./ndk-build APP_ABI=x86 V=1 NDK_TOOLCHAIN=x86_64-4.9
             NDK_APP.local.cleaned_binaries=true --install-dir=/tmp/toolchain
      
    • Note we are compiling for API 22. You can verify the API level of the emulator as follows:
    • [Shell in container]$ /opt/android-sdk/tools/bin/avdmanager  list
      

  3. Create a hello.c file containing e.g.:
  4. #include <stdio.h>
    
    int main(int argc, char **argv) {
      printf("Hello world\n");
    }
    

  5. Compile hello.c
  6.   [Shell in container]$ cd /tmp/toolchain/bin/
      [Shell in container]$ x86_64-linux-gnu-g++-9 -static -o hello ~/hello.c
    

  7. Execute hello.c
  8. (You may get a warning when executing the code, but it should correctly work).
    [Shell in container]$ adb push hello /data/local/tmp
    [Shell in container]$ adb shell /data/local/tmp/hello
    

  9. Enhance the code: the C code should now gather information on the memory and processor usage, and print it every second in the terminal.


Thats'all folks!