Learning Embedded Android N Programming

5 (1 reviews total)
By Ivan Morgillo , Stefano Viola
    Advance your knowledge in tech with a Packt subscription

  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Understanding the Architecture

About this book

Take a deep dive into the Android build system and its customization with Learning Embedded Android Programming, written to help you master the steep learning curve of working with embedded Android. Start by exploring the basics of Android OS, discover Google’s “repo” system, and discover how to retrieve AOSP source code. You'll then find out to set up the build environment and the first AOSP system. Next, learn how to customize the boot sequence with a new animation, and use an Android “kitchen” to “cook” your custom ROM. By the end of the book, you'll be able to build customized Android open source projects by developing your own set of features.

Publication date:
July 2016
Publisher
Packt
Pages
282
ISBN
9781785282881

 

Chapter 1. Understanding the Architecture

In this chapter, the user will learn about Android hardware and software architecture. We will provide an overview on the Android Compatibility Definition Document to properly understand what we need in order to create a fully compliant and certified device.

The user will learn about the Android Application Framework (AAF), the two different Android runtime systems—Dalvik, and ART, and a collection on Google-provided system libraries.

The user will have a first hands-on moment, setting up and running Android Compatibility Test Suite. We will test together an existing certified device and we will take the first step on the path towards the creation of a certified device.

 

An overview of the Android system


Android, as with every other operating system, has a layer-based structure. The next image shows a properly abstracted overview of the whole system architecture:

We can divide the system into the following main layers:

  • Linux kernel

  • Hardware abstraction layer

  • Core libraries and runtime environment

  • Application framework

  • Binder IPC

  • Applications

The software layer closest to the hardware architecture is the Linux kernel. This layer is in charge of communicating with the hardware components and provides an easy-to-use interface for the layer above.

Moving up on the architecture path, we have Android runtime and core libraries. This layer provides the basics tools for the application framework. The application framework is a collection of ready-to-use components that the system provides to the Applications layer via the Android SDK. The top layer contains all those applications we use everyday—games, productivity apps, multimedia, and so on.

Linux kernel

Android is based on the Linux kernel, but it's not a classic Linux-based desktop system: it's not Ubuntu. However, Android architecture designers and developers rely on the Linux kernel, because it's open source, it's extensively tested worldwide, and it can be easily tailored to fit Android-specific hardware needs, on any kind of device.

From a very pragmatic point of view, choosing to base the system on an open source heart reinforced the Android philosophy of being an open system, supported by its community and trusted by enterprise companies, thanks to its transparency. Besides, this approach saved a lot of development time—they didn't have to start from scratch and they could focus on the rest of the architecture, taking advantage of a popular and well-documented core.

The vanilla Linux kernel needed some love to properly fit all the Android requirements. Most of the contributions by Google were focused on:

  • Fixing bugs

  • Enabling new hardware

  • Improving power management

  • Improving error reporting

  • Improving performance

  • Improving security

From a hardware point of view, the Android team made a great effort to add new goodies to the Linux kernel. Lots of fixes and hacks were released to improve Bluetooth support and management, lots of General Purpose Input/Output (GPIO) drivers were added, ARM compatibility was enhanced, as ARM was the primary Android-supported architecture and also MMC management received lots of contributions. The new ADB gadget driver was added to help developers to communicate via USB with external devices.

From a memory point of view, the Android team introduced PMEM, the process memory allocator. This gave the ability to manage large physically contiguous memory regions between user space and kernel space. Working in a specific low-resource hardware domain, the Android team released Ashmem, Android Shared Memory, which targeted low-memory devices and provided an easy-to-use file-based API to manage shared memory, especially under memory pressure.

From a power management point of view, the Android team introduced an improved suspend system, wakelocks, and Android Alarm Timers, the kernel implementation to support Android Alarm Manager.

The other interesting contributions were the kernel support for Android logcat command, that provides logs of system messages, application debug messages, and exceptions, and Android Binder, an Android-specific interprocess communication system, used for remote method invocation too.

Hardware abstraction layer – HAL

To overcome the increasing hardware fragmentation, Android engineers created an abstraction layer that allows the system to interact with the hardware just being aware of a specific intercommunication interface. The system completely ignores the low-level implementation of hardware and drivers. This approach enforces the idea of developing software against an interface instead of against an implementation. With this approach, the Android system does not know and does not need to know how hardware is accessed or managed.

As a mid-level layer between the hardware and the system, Android HAL is commonly developed using native technology—C/C++ and shared libraries. There is no constraint from Google about how we need to implement our HAL and our device drivers: it's up to us to design it as we think best for our scenario. There is only one simple rule:

Our implementation must provide the same interface that the system is expecting.

Libraries and the application framework

Going up on the architecture ladder, we find the two most important software layers. The Android application framework and Android system libraries are the middleware between the bare hardware, managed by the Linux kernel, and all those fancy, shiny apps we have on our smartphones.

Libraries

Android system libraries are a set of libraries, specifically created to work on Android, to allow and help with system components and app development. The most important are:

  • SQLite: SQLite is the entry point to the SQL world. It's a tiny SQL implementation for embedded systems and it provides a standard way to access data published by content providers or SQL DB created by the user.

  • SSL: SSL provides the standard security environment for network communication.

  • OpenGL: OpenGL libraries are the link between the Java (and C/C++ JNI) world and the OpenGL/ES 3D graphics rendering API.

  • SGL: SGL provides a way to access 2D rendering engine.

  • Media framework: Media framework provides codecs for rendering, recording, and playback for the most common media formats.

  • WebKit: WebKit is the popular HTML rendering engine.

  • libc: The libc library is a BSD-derived implementation of the standard C library, specifically tuned to best perform on embedded Linux-based devices.

  • Surface manager: Surface manager manages access to the display subsystem.

The application framework

This is the core of the Android software ecosystem. It provides a plethora of managers that facilitate the most common tasks of Android developers and the Android system itself. The most important components of the Application Framework are:

  • Activity manager: This provides the navigation backstack and manages the Android activity lifecycle

  • Resource manager: This provides access to noncode resources contained in the apps: graphics, localized string, styles, and colors

  • Location manager: This is in charge of providing the most accurate position information, using data collected by the GPS sensor, from cell towers and Wi-Fi networks nearby

  • Notification manager: This enables apps to display notification alerts in the status bar, according to Google Design Guidelines, to provide a common and familiar user experience

  • Content providers: This provides a common approach to share data between different apps, for instance, accessing contacts data or sharing a common data set between two apps

  • Views and widgets: These comprise the UI core of the Android experience. Buttons, text fields, and layouts are the building blocks of every Android system component and user app

Everything on Android is achieved using the official Android SDK that provides a consistent and documented way to use all these system managers, views, and logic components to let you create the next big hit of the Google Play Store.

Binder IPC

From an Application Framework point of view, the Binder Inter-Process Communication (IPC) is a hidden layer. It takes care of creating a transparent communication channel between the high-level Android API, accessible via the Android SDK, and the actual Android system.

The application layer

All the applications created by third-party entities, such as smartphone manufacturers or Android programmers will be installed on the application layer.

Usually, this relies on a read/write area of the handset solid memory, but for software provided by manufacturers, typically, it uses a read-only memory area to be sure that these applications will always be installed no matter what. Apps such as Google Maps, YouTube, Samsung TouchWiz Nature, and HTC Sense are examples of apps in this very group: they are shipped with the device's operating system, they are installed on a read-only memory area of the device, and they are meant to be uninstallable as a core component of the system.

As we will see, this is not 100% true—once you have the proper skill set, you will be able to manipulate the whole system. In the following chapters, you will acquire these skills and you will learn how to heavily modify an already existing Android version and get rid of those apps, if necessary.

 

Android compatibility


Every successful Android device on the market, before being launched, has been certified. Manufacturers have designed, developed, and tested their device according to precise guidelines, rules, and constraints.

To make the task as easy as possible, Google has created the Android Compatibility Program that defines details and tools that help OEMs to create a device that will properly support the OS, the SDK, and the developers' expectations:

"To run Android apps on a variety of Android devices."

As a manufacturer, creating and distributing a certified device has critical importance. Our goal is to create a device with a unique, but at the same time familiar, user experience: we have to be cool, but not weird! Users want to customize their Android device and they want to be sure that their favorite apps will run smoothly, without problems of any sort. Developers want to be sure that they won't waste time fixing bugs on every different smartphone, tablet, or TV—they want a common ecosystem on which they can rely.

A well-defined and well-supported ecosystem brings more certified devices that bring more and more developers that bring more and more happy users. The following diagram shows exactly how the Android ecosystem lives thanks to the constant creation of well-designed, well-produced, certified devices:

The Android Compatibility Definition Document

The Android Compatibility Definition Document (CDD) is Google's way to specify guidelines, rules, and constraints to be considered for an Android-compatible device. Every device designer and manufacturer has to refer to the CDD to be able to easily port Android onto its own hardware platform.

For each release of the Android platform, Google provides a detailed CDD. The CDD represents the policy aspect of Android compatibility and its role is to codify and clarify all the requirements and eliminate any ambiguity. The main goal is to provide rules for manufacturers to let them create complex hardware devices, compatible with Android SDK and Android apps.

Designing and developing a new device is no easy task. Even the smallest detail matters. Think about OpenGL support. There is no possible way to be sure that the graphical experience will be great for the user. The only thing that's possible is working according to the guidelines and then "test, test, and test". That's why providing as many details and guidelines as possible is the only way to help the manufactures to achieve their goal.

However, the CDD does not attempt to be comprehensive—it couldn't be. It just serves as guidance to approach as easily as possible the final goal—a compatible device. Further help comes from the source code itself and from the Android SDK API that can be considered a compatibility-proof test bench. Think about CDD as an overview of the minimum set of constraints to be compliant with: it's the very first step of the journey.

Device types

In the beginning, Android was born to run on digital cameras. Luckily for us, a lot has happened since then: smartphones invaded our world! Then we had tablets and mp3 players. Nowadays, we have TVs, watches, media centers, glasses, and even cars, running Android and Android apps. Every device on the market will probably land in one specific category, according to its features. CDD gives a few pointers about which category your new device would be placed in:

  • Every device with an embedded touchscreen, a power source that allows mobility, and that can be held in hand can be considered an Android Handset.

  • An Android Television device is a device designed for media content: video, music, TV, games, with users sitting about three meters or ten feet away. This kind of device must have an embedded screen or an output video interface—HDMI, VGA, DVI, or a wireless display port.

  • A device designed to be worn on a wrist, with a touchscreen display with a diagonal between 2.79 cm and 6.35 cm is considered an Android Watch.

  • Having a car with an infotainment system, based on Android, gives us an Android Automotive implementation.

Software compatibility

From a software execution point of view, the basic requirement is being capable of executing the Android Dalvik bytecode. Our device must support the Android Application Programming Interface and must provide complete implementations of any documented behaviors of any documented API exposed by the Android SDK or annotated with the @SystemAp annotation.

Hardware compatibility is a tricky task, because even if our device is lacking some specific hardware, for instance GPS or accelerometers, our implementation must contain GPS-related code and should be capable of handling inappropriate requests in a reasonable way to avoid crashes or misbehaviors.

One of the main players of software compatibility is the ability of our device to support intents. Every device properly implementing Android API must support Android loose-coupling intent system. Intents allow Android apps to easily request functionality from other Android components and avoid the effort to implement everything from scratch. The Android system has a set of core applications that implement the intent pattern:

  • Desk clock

  • Browser

  • Calendar

  • Contacts

  • Gallery

  • Global Search

  • Launcher

  • Music

  • Settings

As a vendor, we could integrate the default Android components or implement our own component, according to the public API. Those components will have special system permissions to act as system apps and they will be the first proposed choice for the matching intent filter.

For instance, when a developer ask to open a web page, the system will suggest "our browser component" as the first chosen app to perform the task. Of course, being a good citizen means that we must provide a proper settings menu to give the user the possibility to override our default choice and let the final user pick a different app for the task.

 

Beyond Java


Android applications development is mostly based on Java programming. The SDK is based on Java, the runtime system is fully compliant with Java6, partially with Java7, and Google is already experimenting with Java8. Most developers will easily approach the platform if they already know Java programming language. However, Android offers a lot more to those developers that are dealing with heavy-duty, performance-oriented scenarios: Android Native API.

Native API

Native API gives the developers the opportunity to call native C, and partially C++, code from an Android Java application. Native code is compiled as standard ELF .so files and stored in the app APK file. Being native code, it has to be compiled for every architecture we are going to support, because, contrary to the bytecode, it can't be built once and run on every architecture.

As integrators, we must embrace one or more Android Application Binary Interfaces (ABIs) and aim for having full compatibility with the Android NDK. Of course, Google provides guidelines and constraints to easily reach this goal. These are the basic rules for proper compatibility:

  • Our implementation must include support for code running in the managed environment, that is Java code, to call into native code, using the standard Java Native Interface (JNI) semantics

  • If our implementation supports the 64-bit ABI, we must support its relative 32-bit version, too, because we must provide compatibility to non-64 bit potential devices

  • Google suggests that we build our implementation using the source code and header files available in the Android Open Source Project—just don't reinvent the wheel

From a libraries point of view, our implementation must be source-compatible (that is, header compatible) and binary-compatible (for the ABI) with all the following libraries:

  • libc (C library)

  • libm (math library)

  • liblog (Android logging)

  • libz (Zlib compression)

  • libdl (dynamic linker)

  • libGLESv1_CM.so (OpenGL ES 1.x)

  • libGLESv2.so (OpenGL ES 2.0)

  • libGLESv3.so (OpenGL ES 3.x)

  • libEGL.so (native OpenGL surface management)

  • libjnigraphics.so, libOpenSLES.so (OpenSL ES 1.0.1 audio support)

  • libOpenMAXAL.so (OpenMAX AL 1.0.1 support)

  • libandroid.so (native Android activity support)

  • libmediandk.so (native media APIs support)

These libraries also provide minimal support for the C++ JNI interface as well as support for OpenGL.

An implementation of each one of these libraries must be present in our system to be compatible with Android NDK. This is a dynamic list and we cannot treat it as a definitive set of libraries: future versions of Android could add new libraries and increase development possibilities and scenarios. That's why native code compatibility is challenging. For this reason, Google strongly suggests to use the implementations of the libraries listed earlier from the Android Open Source Project, taking advantage of the Open Source philosophy of Android and to enjoy well-supported and well-tested source code.

Maintaining 32-bit support

Nowadays, all major manufactures are switching to 64-bit architecture and new ARMv8 architecture deprecates lots of old CPU operations. Unfortunately, the market is still full of 32-bit compatible software and even on 64-bit architecture we must still support these deprecated operations, to avoid scaring developers and losing precious market share. Fortunately, we can choose to make them available via real hardware support or software emulation, at the expense of performance.

Supporting 32-bit architecture can be very tricky. We can just think about one simple scenario, for example, accessing the /proc/cpuinfo file. Legacy versions of the Android NDK used /proc/cpuinfo to discover CPU features. For compatibility with applications built using 32-bit NDK, we must specifically include the following things in /proc/cpuinfo when it is read by 32-bit ARM applications:

  • Features: This is followed by a list of any optional ARMv7 CPU features supported by the device

  • CPU architecture: This is followed by an integer describing the device's highest supported ARM architecture (for example, 8 for ARMv8 devices)

The tricky part is that these requirements only apply when /proc/cpuinfo is read by 32-bit ARM applications. The file must be not altered when read by 64-bit ARM or non-ARM applications.

 

From Dalvik to ART runtime


The original Android runtime implementation was Dalvik. Dalvik was a virtual machine, specifically created for Android, due to the necessity to target low-memory devices. It was an integral part of the system until Android KitKat.

As we already said, Android applications are mostly written in Java. When Dalvik was the in-use runtime system, the Java code was compiled into bytecode. This bytecode was then translated to Dalvik bytecode and finally stored into a .dex (Dalvik Executable). After this procedure, Dalvik was able to run the Android app.

Although Dalvik had been designed for slow devices, with low memory, its performance has never been astonishing, not even when the Just-In-Time compilation was introduced, back with Android 2.2 Froyo. Dalvik JIT was supposed to bring a huge performance boost to Android apps and, from some points of view, it did, but with limitations, such as the infamous maximum methods number, and the pressure from alternative solutions forced Google to look forward to a new runtime:

The Android runtime

When Android 4.4 KitKat was released, users could select a new experimental runtime environment in the Settings menu: ART. Android RunTime or, shortened, ART, is the current default runtime solution that replaced Dalvik from Android 5 Lollipop. The previous diagram shows a comparison between Dalvik and ART architecture.

The idea behind Dalvik's JIT (just-in-time) execution was to profile the applications while they were being executed and dynamically compile the most-used segments of the bytecode into native machine code. Native execution of these most-used segments called traces would then greatly speed-up the execution of the application even though most of the code would still be interpreted.

A new old approach – AOT compilation

Art re-introduces the concept of AOT (ahead-of-time) compilation. It works as most compilers do, that is, it compiles the whole application code into the native machine code, without interpreting bytecode at all. This takes some time, but it is done only once when the user downloads the app, so considering the time and amount of resources needed for JIT profiling and optimization that are needed on every application start, it is an acceptable trade-off. Also, since the whole application is now compiled, it is quicker overall and the power consumption is reduced, which improves the device autonomy.

ART is the default runtime since Android 5, but Android needs to ensure compatibility with all those apps that are already on the market and all those devices that are running a previous version of Android and won't receive any operating system updates.

For backward compatibility reasons, the input bytecode is the same for ART and Dalvik. The application APK file still contains standard .dex files, but replaces the .odex files (Optimized Dalvik Executables) with the standard Unix ELF files (Executable and Linkable Format). During the installation, ART uses dex2oat utility to compile the bytecode into native code stored in the ELF file. As already mentioned, this step is performed only once and requires fewer resources and less overhead than Dalvik's JIT compilation. The downside is that the APK files are larger because they effectively contain double the code (uncompiled bytecode and compiled executable). After this compilation, the system will run just the ELF executable.

The bottom line is faster apps, but a bit less free space on your smartphone memory.

Garbage collection and other improvements

AOT compilation is not the only improvement that ART brought in. One of the most important features is the improved garbage collection. Garbage Collection (GC) is a form of automatic memory management, completely different from the old idea where the developer was the one in charge of allocating memory when needed and freeing it when it was not needed anymore.

The whole philosophy is based on the concept of Garbage Collector, an entity that tries to reclaim memory occupied by objects that are not used anymore in the program. It's a well-known tool in the Java world and Android has always suffered from its downside—GC is very slow and blocking.

Android 2.3 introduced the concurrent garbage collector—GC is not blocking the app anymore when it occurs, but there will always be an overall slowdown when it occurs. Finally, ART introduced a few more performance improvements:

  • Just one pause for garbage collection instead of Dalvik's two pauses

  • GC processing is now parallelized, reducing the duration of the GC pause

  • New Rosalloc memory allocator that uses thread-local region allocations for smaller objects and separate locks for bigger objects, instead of a single global lock

  • Full garbage collection is run only when the phone is locked so that the user doesn't notice when the GC is run

  • There is a compacting GC that reduces memory fragmentation and so diminishes the need to kill other applications just because bigger contiguous memory chunks are needed

From a development and debugging point of view, ART brought in the support for sampling profiler, support for more debugging features, and improved diagnostic details in exceptions and crash reports.

Waiting for Android Nougat

The upcoming version of Android will bring some enhancement to the current ART runtime. Google will introduce a so-called Profile-guided JIT/AOT compilation. JIT stands for Just In Time and looks similar to the old Dalvik approach: a compiler with code profiling capabilities. This JIT compiler will work together with ART and will provide constant performance improvement as it will continuously be profiling code and resource usage.

To improve performance during the installation phase, ART won't pre-compile Ahead-Of-Time the whole app. Instead, thanks to the profiling approach, it will detect hot methods in the app and will only pre-compile them, leaving unused parts of the app uncompiled. This precompilation process is smartly performed when the device is idle and charging, to have the smallest negative impact on the user experience and allow the user to install in instants apps that in Android 6 would take several seconds to be installed.

This whole new approach aims to improve applications and system performance on low end devices, reducing RAM memory footprint, battery draining and increasing runtime performance, for a satisfying Android experience on a wide range of devices.

 

Meeting the Compatibility Test Suite


We are aware of the CDD and we did our best to create a compatible device. A lot of aspects could still have glitches and we surely want to get rid of them. To make sure that everything works as expected, our Android implementation must be tested with Android Compatibility Test Suite. Android CTS will accompany us throughout the journey to our certified device. We will constantly use it to keep an eye on what is working and what is not working yet.

Every new version of Android platform comes with a new Compatibility Test Suite (CTS). This automated testing suite has two main components:

  • Tradefed, that manages text execution from the desktop.

  • Test cases executed on the Device Under Test (DUT). These cases are regular JUnit tests written in Java and packaged as Android .apk files so that they can be executed on the target device.

There is also the CTS Verifier, a tool for manual testing that consists of the verifier app that is executed on the device and collects the test results; and other executables or scripts that are executed on the desktop machine in order to provide further data or control for some test cases in the Verifier app.

The following diagram shows the CTS workflow:

The test suite on your computer will install the test on the device and will launch it. The device will test that particular subset of features and will give the results back to the test suite on your computer. The test suite will store these results, install the next test, and will start the cycle again, until every test is executed.

Currently, the CTS provides two main types of test cases:

  • Unit tests

  • Functional tests

Unit tests test the smallest logical units of code within the Android platform, for example, a single class, such as java.util.HashMap.

Functional tests are used to test a specific function that can consist of numerous API method calls.

Google is planning to provide more tests in the future versions of the test case. A couple of ideas are:

  • Robustness tests: This tests the system's durability under stress conditions

  • Performance tests: This tests the system's performance, such as frames per second

The following table shows the areas covered by the Compatibility Test Suite:

Area

Description

Signature tests

For each Android release, there are XML files describing the signatures of all public APIs contained in the release. The CTS contains a utility to check those API signatures against the APIs available on the device. The results from signature checking are recorded in the test result XML file.

Platform API Tests

These tests test the platform (core libraries and Android Application Framework) APIs as documented in the SDK Class Index to ensure API correctness, including correct class, attribute and method signatures, correct method behavior, and negative tests to ensure expected behavior for incorrect parameter handling.

Dalvik Tests

These tests focus on testing the Dalvik Executable Format.

Platform Data Model

The CTS tests the core platform data model as exposed to application developers through Content Providers, as documented in the SDK android.provider package: contacts, browser, settings, and so on.

Platform Intents

The CTS tests the core platform intents as documented in the SDK Available Intents.

Platform Permissions

The CTS tests the core platform permissions as documented in the SDK Available Permissions.

Platform Resources

The CTS tests for correct handling of the core platform resource types, as documented in the SDK Available Resource Types. This includes tests for: simple values, drawables, nine-patch, animations, layouts, styles and themes, and loading alternate resources.

CTS setup

Our journey will be very practical and hands-on, that's why in this section we are going to set up Android Compatibility Test Suite to test an existing device. We can't start working on our own Android implementation without knowing what we are going to support and test. To be able to run Android CTS, we will need:

There are a lot of files to download. In the meantime, we will set up our device.

Device setup

We are testing an existing device, a smartphone, so we are already satisfying needs such as having a screen and we can move to device software configuration.

Tests should be executed on a clean device, so we should run a Factory Restore to erase all the data on the smartphone. Be sure of having a backup of your data if you are not using a development device. On Android 4.4 KitKat, you can reach the specific menu by navigating to Settings | Backup & reset | Factory data reset.

This will take a while—the device will shut down and the erasing process will start. The procedure will remove every single byte that is not part of the original Android system provided with your device, restoring all the settings and bringing the device to its original setup.

When the device restarts, we need to select English US language by navigating to Settings | Language & input | Language.

Now we need to turn on the Location: We need Wi-Fi and GPS and we need to provide some Internet connectivity. We need to disable any Screen Lock by navigating to Settings | Security | Screen Lock = 'None'.

We need a few settings from the Developer options menu. On a brand new installation of a vanilla Android system this menu is hidden. We can enable using the following steps:

  1. Navigate to Settings | About phone.

  2. Scroll to the bottom.

  3. Tap continuously on build number item.

  4. You are now a developer!

Note

If you are working with an HTC, Samsung, or Sony device and its custom version of Android, the previous steps could be a bit different. We leave it as an exercise to find the right navigation path for your non-vanilla Android version.

Once the Developer options menu has been enabled, navigate back to the Settings screen. In the Developer options menu, we need to enable the following:

  • USB debugging

  • Stay awake

  • Allow mock locations

Before running any tests, it's important that the device is on a steady support to avoid triggering accelerometers and the gyroscope. The camera should be pointing to a focusable object. Don't press any buttons or keys during the tests—this could invalidate test results.

Media files setup

To properly run all the tests, we will need a few multimedia files on the device—Android CTS media files. First of all, let's connect the device to the USB. If this is the first time that you connect this device to this host PC, the device will display a dialog to authorize the connection—allow the connection:

Any Android device can communicate with a host PC using Android ADB. This key tool is covered in great detail in the next chapters, so, for now, we can start downloading the latest Android SDK from https://developer.android.com/studio/index.html#downloads, according to your platform. Once the download is completed, decompress the file and you will be provided with an android-sdk folder, containing a platform-tools folder, containing adb executable.

Back to our media files setup now:

  1. Open a terminal.

  2. Navigate to the downloaded file, for instance:

    $ cd ~/Downloads
    
  3. Unzip the file:

    $ unzip android-cts-media-1.1.zip
    
  4. Enter the brand new android-cts-media folder with:

    $ cd android-cts-media
    
  5. This folder contains a file that we must make executable:

    $ chmod u+x copy_media.sh
    
  6. Now we are ready to copy all the media files we need onto the device:

    $ ./copy_media.sh all
    

The next screenshot shows the output of the whole procedure:

Run!

Everything is in place now and we can use cts-tradefed to run some test plans. Move to the Android CTS folder and run the following command to enter the cts console:

$ ./tools/cts-tradefed

The previous screenshot shows how cts-tradefed automatically identifies our connected device and gets ready to test.

CTS console provides a few useful commands:

  • list plans: This will list all the available test plans in the repository

  • list packages: This will list all the available test packages in the repository

  • run: This will allow us to run all the tests we want

Typically, the following test plans are available:

  • All CTS tests required for compatibility

  • Signature tests the signature verification of all public APIs

  • Android tests for the Android APIs

  • Java tests for the Java core library

  • VM tests for ART or Dalvik

  • Performance tests for your implementation

As our first approach to CTS, we are going to run CTS plan:

cts-tf > run cts --plan CTS --disable-reboot

The testing will start immediately and the console will be full of log messages in the blink of an eye, as shown in the following screenshot:

Now, grab some coffee or make some good tea: this will take a while. cts-tradefed will test everything that is possible to test with an automatic test. Luckily for us, there is a lot that can be tested in this way.

Analyzing the test results

Time has passed, the tea has gone, and the tests are over. On a quad-core smartphone, such as a Motorola Moto G or Nexus 4, this could take up to 10 hours. Eventually, we have got some nice results to check out. According to the folder's path we are working in, we will have results in a .zip file in the cts folder:

$ unzip ~/bin/android-cts/repository/results/START_TIME.zip

Unzipping the file, we will find a testResult.xml file. Opening this file with a recent web browser (Firefox is working fine here) will show plenty of meaningful tables, with all kind of test and results. The next screenshot shows the initial Test Summary. We have information about the test duration, how many tests were executed, how many tests passed, and how many tests failed:

As you can see, even testing a certified smartphone, currently on the market, will produce some failed tests. This gives you an idea about the complexity of producing the perfect Android device.

The next screenshot shows Test Summary by Package, specifying the test results one test after the other. For brevity, we are showing just a subset of the results:

The previous Test Summary screenshot shows that 29 tests have failed. If we dig into the test result file, we see that detailed reports are also available. This further information is hugely useful to precisely spot the failed test, like the one in the following screenshot, and investigate the issue:

The test result file tries to play polite and, for brevity, does not show the full stacktrace of the failed test. To reach the stack trace of the failure, we must inspect the source code of testResult.xml. For every executed test, there is a corresponding <Test> tag. For those tests that failed, we will have a <StackTrace> tag too. That's what we are looking for!

As a final note, testResult.xml contains a huge section with all the information about the device it has been able to retrieve. It's a very large amount of data that, for brevity, we are not reporting here, not even as an example.

 

Diving deeper with CTS Verifier


We already know that there are lots of APIs and functions that we can automatically test with cts-tradefed, but what about all the other APIs and functions that cannot be tested within an automated environment?

CTS Verifier comes in every time an API or a function cannot be tested on a device without manual input. These are scenarios involving audio quality, touchscreen effectiveness, accelerometer precision and reactivity, camera quality, and features that are meant so specifically for human interaction that they are impossible to test without human interaction.

Setup

All we need to run CTS Verifier is an Android certified device and the appropriate CTS Verifier APK file. As we are testing an Android 4.4 device, we need to pay attention to downloading the proper CTS Verifier version. You can download the APK for your Android version and device architecture here: http://source.android.com/compatibility/downloads.html.

You just need to unzip the downloaded file and you will find a folder hierarchy and two .apk files. You can install CtsVerifier.apk using ADB:

$ adb install –r CtsVerifier.apk

The following screenshot shows the properly installed CTS Verified app and the initial screen:

Manual testing

As we know, CTS Verifier contains tests that need manual input to execute, evaluate, pass, or fail. Every test has its own Info screen that helps the tester to perform the test. As an example, we will run the Accelerometer Test, in the Sensors section.

Launching the test, we are welcomed by the info screen, as shown in the following screenshot:

The Info button explains how to perform the test and what to evaluate. As we move into the testing, we can evaluate if the accelerometer is working as expected. The following screenshot shows three different moments of the test:

  • The smartphone lays on the desk

  • The smartphone is held in hand, in portrait mode

  • The smartphone is held in hand, in landscape mode

As specified in the Info button, the arrow is always pointing in the same direction as the gravity: the sensor is working properly. We can consider that we have passed the test and click on the Pass button.

We have passed our first test. CTS Verifier provides dozens of tests and, one by one, we are going to run, verify, and pass them, in the long journey towards our first Android Certified Device.

Retrieving the results

When every test has been executed, we can save the result using the Save icon in the top-right corner of the initial screen, as shown in previous screenshot. The results will be saved on the device and a dialog box will show the precise path, as shown in the following screenshot:

Now, let's open a terminal and copy all the results from the phone to our computer:

$ adb pull /mnt/sdcard/ctsVerifierReports/ .
$ unzip *.zip

At this point, we have a ctsVerifierReport-[…].xml with all the info about our manually executed tests.

Congratulations! You have fully tested an Android device. Step 0 of our journey is complete.

 

Summary


In this chapter, we learned what we are going to need to create a certified Android device. We saw the Android Compatibility Definition Document and we learned how to design a system to match the Android architecture. We had an overview of the two different runtime systems: Dalvik and ART and their main differences.

We had a full immersion into Android device testing, we learned how to run CTS automated tests and CTS manual tests on a already certified device.

The next chapter will be very hands-on. We will learn how to retrieve Android source code and we will understand the code structure and organization.

About the Authors

  • Ivan Morgillo

    Ivan Morgillo is a computer engineer, a conference speaker, and a community organizer. He is passionate about programming and embedded systems—from DIY domotics to Android devices.

    He is cofounder of Alter Ego Solutions, a mobile development consulting company.

    He is also the author of RxJava Essentials, by Packt Publishing and Grokking Rx, by Manning Publications.

    Browse publications by this author
  • Stefano Viola

    Stefano Viola is an embedded software developer with proved experience with Linux embedded devices and microcontrollers. He is an Android platform expert and application developer. He is passionate about programming and embedded systems, from DIY domotics and robots to customized Android devices.

    He is currently working at SECO as an embedded software engineer. He is part of AXIOM project, an R&D project by the European Community, and the UDOO team.

    Browse publications by this author

Latest Reviews

(1 reviews total)
This Book is a state-of-the-art content about Android Embedded development, without missing a thing and dealing with Android N.

Recommended For You

Learning Embedded Android N Programming
Unlock this book and the full library for FREE
Start free trial