Android Security: A walk-through of SELinux

Summary

In DAC, each process has a owner and belong to one or several groups, and each resource will be assigned different access permission for its owner and group members. It is useful and simple. The problem is once a program gain root privileged, it can do anything. It has only three permissions which you can control, which is very coarse.
SELinux is to fix that.
It is much fine grained. It has lots of permissions defined for different type of resources. It is based on the principle of default denial. We need to write rules explicitly state what a process, or a type of process (called domain in selinux), are allowed to do. That means even root processes are contained. A malicious process belongs to no domain actually end up can do nothing at all. This is a great enhancement to the DAC based security module, and hence the name Security-Enhanced Linux, aka SELinux.
In this article, we'll have a walk-through of various components of SELinux on Android. We will take a top-down approach. The reason is SELinux has lots of concepts to understand, and files to manipulate, so quite likely, you will won't get the big picture if I were to start with the details first.
However, it is also possible that this approach will create more confusing. But let's try anyway.

How SElinux works

The core idea of SELinux is to label every resources and processes, and on the base of default denial, to craft explicit rules granting a process certain permissions to access the resources.
Let's break it down.
  1. Define resource types, and label the resources
  2. Define process domains, and label the processes
  3. Write rules that grant a process the permissions
  4. Rules in action.

Define resource types, and label the resources

Define resource types

Use the type keyword and declare it in a .te file. The suffix te stands for Type Enforcement and no surprise, type are defined in this file.
Specifically, in Android:
  • Types for (normal) files are defined in the /system/sepolicy/file.te.
  • Types for devices files are defined in the /system/sepolicy/device.te.
  • Types for executables files are defined in individual domain files, e.g /system/sepolicy/mediaserver.te for mediasever domain.
Here is the example for each type of te files:
Code snippet of file.te:
# Filesystem types
type labeledfs, fs_type;
type pipefs, fs_type;
type sockfs, fs_type;
type rootfs, fs_type;

# proc, sysfs, or other nodes that permit configuration of kernel
type proc_bluetooth_writable, fs_type;
type proc_cpuinfo, fs_type;
type proc_iomem, fs_type;
type proc_meminfo, fs_type;
type proc_net, fs_type;

type adb_data_file, file_type, data_file_type;
Code snippet of device.te:
type audio_device, dev_type;
type binder_device, dev_type, mlstrustedobject;
type block_device, dev_type;
type camera_device, dev_type;
Code snippet of mediaserver.te, an example domain te file. (Domain te files also include other important things but at this moment, we'll focus on the type definition only.)
#/system/sepolicy/mediaserver.te:
type mediaserver_exec, exec_type, file_type;
A few takeaways:
  • It is really a very fine grained type system. Take a look at those different types of proc_xxx. Because of this fine grained labelling, we can write accurate rules that will only allow a process to access a very narrow subset of resources, or even a single file, when that type labels only a single file.
  • It is targeted and designed for Android. See the adb_data_file.

Label the resources

To label a resource is also called to create a Security Contexts for a resource, or file contexts. The file contexts common to all devices are put in system/sepolicy/file_contexts. Vendor specific file contexts should reside in device/vendor/device/sepolicy. They will be combined together to generate the final file context during the build process.
Let's take a look at the common file_contexts.
# system/sepolicy/file_contexts
# truncated to show an overall view

# Root
/fstab\..*          u:object_r:rootfs:s0
/init\..*           u:object_r:rootfs:s0
/ueventd\..*        u:object_r:rootfs:s0

# Dev
/dev/audio.*        u:object_r:audio_device:s0
/dev/binder         u:object_r:binder_device:s0

# System
/system/bin/mediaserver     u:object_r:mediaserver_exec:s0
/system/bin/servicemanager  u:object_r:servicemanager_exec:s0
/system/bin/surfaceflinger  u:object_r:surfaceflinger_exec:s0

# Vendor
/vendor(/.*)?               u:object_r:system_file:s0
/vendor/bin/gpsd            u:object_r:gpsd_exec:s0

# ODM/OEM
/odm(/.*)?                  u:object_r:system_file:s0
/oem(/.*)?                  u:object_r:oemfs:s0

# Data
/data/security(/.*)?  u:object_r:security_file:s0
/data/drm(/.*)?   u:object_r:drm_data_file:s0
/data/gps(/.*)?   u:object_r:gps_data_file:s0
A few takeaways:
  • It labels everything : normal file, device file, executables.
  • It labels everywhere : rootfs, system, vendor, data partitions.
  • It is tailed for Android, sometime its called SEAndroid.
The label follows form of user:role:type:sensitivity. From the example shown above, you can tell type is the most important part, since the other part are same in Android at the moment.
To check the context for files use ls -Z
$ ls -Z /system/bin/mediaserver
u:object_r:mediaserver_exec:s0 /system/bin/mediaserver

Define process domains, and label processes

Domain is similar to Type but used to label a process, instead of a file. To define a domain, use type keyword as well, but the second parameter is domain instead of xxx_type. See line (1) in follow code snippet.
/system/sepolicy/mediaserver.te:
    # mediaserver - multimedia daemon
    type mediaserver, domain, domain_deprecated;          (1)
    type mediaserver_exec, exec_type, file_type;          (2)  

    net_domain(mediaserver) 
    init_daemon_domain(mediaserver)                       (3)
However, labelling a process with a Domain is different from labelling the corresponding executable file (with a Type). For example, we know from preceding introduction that the /system/bin/mediaserver is labelled as u:object_r:mediaserver_exec:s0, and that's down to the mediaserver_exec type.
But, the domain of the process mediaserver of is mediaserver. And, we'll see late, when writing the rules, we will use domain mediasever, instead of mediaserver_exec.
$ ps -Z | grep mediaserver
u:r:mediaserver:s0    media   1662  1 44340  10456 /system/bin/mediaserver
It's not hard to imagine there is something done under the hood creating this association (or transition) between the exec type and process domain. That's done through the macro in line (3). For now, we can just pretend we know what it is.

Write rules that will apply to a process and resources.

A rule will roughly say "allow somebody do something on something". Or better, "allow a subject take some actions on an object". The subject here is the process; the object here are the resources, such files, sockets; and the actions are the permissions. We have already know how to label the subject and object, in order to write a rules, we also need to define the permission.

Permissions

In DAC, we have three access permissions, read, write, execute, for all type of files. In SELinux, things are much more complex, for a good reason.
SELinux (or SEAndroid) defines a list of types, called security classes. Its includes File, Directory, File System, Socket, Processes, security and capability. A full list can be found at system/sepolicy/security_class.
For different classes, there are different permissions, or called access vectors. A full list can be found at system/sepolicy/access_vectors.
An simple explanation of the permissions defined by SELinux can be found here.
Among those security classes, there is a class called Process, which defines the permission a process itself can do, for example, whether the process is allowed to change the security context of its own and the child processes. This constraint can be done in DAC based model.

Final, write the policies.

Policy files is the place to put all the pieces together and do the ultimate job of imposing access control.
The policy file ends with .te suffix as well, same as the type definition files. They are organized by domains, for example bluetooth.te for bluetooth domain/service/daemon, mediaserver.te for mediaserver domain/service/daemon.
The format of the rule is:
rule_name source_type target_type : class perm_set;
Below is truncated code of mediaserver.te. It shows an example of how to control the access of different type of resources: files, directories, devices, sockets, process, and binder services. Most of the rules are (hopefully) self explanatory, if you had followed the discussion (and congratulation on that). What worth note is the ability to control the out going bind calls. It means you have add that explicitly in the policy file, if you want to use a new binder service, or call a new API of a binder service. This is really tough, and some may consider it is cumbersome. However, it makes the system more secure. Everything vital permission must be explicated allowed. That is the core idea of SELinux, or Mandatory Access Control (aka MAC) in general.
# /system/sepolicy/mediaserver.te:
# truncated, an example for different type of permissions: 

# files
allow mediaserver media_data_file:file create_file_perms;
# dirs
allow mediaserver oemfs:dir search;
# devices
allow mediaserver gpu_device:chr_file rw_file_perms;
allow mediaserver video_device:dir r_dir_perms;
# socket
allow mediaserver rild:unix_stream_socket { connectto read write setopt };
# process
allow mediaserver self:process ptrace;
# bind service
allow mediaserver activity_service:service_manager find;
use_drmservice(mediaserver)
allow mediaserver drmserver:drmservice { setPlaybackStatus openDecryptSession }
allow is the most used rule, and that is conform to the selinux's default denial model. There is also other rules, such as neverallow. This rule specifies that an allow rule must not be generated for the operation, even if it has been previously allowed.
For example, app.te states that app are never allowed to access the hardware device files. It is also a requirement in CTS, the neverallow rules in system/sepolicy are never allowed to be modified.
system/sepolicy/app.te
# Access to any of the following character devices.
neverallow appdomain {
    audio_device
    camera_device                                            
    dm_device
    gps_device
    radio_device
    rpmsg_device
    video_device
}:chr_file { read write };

Rules in actions

sepolicy(.bin), file_context.bin and policy.conf

We have discussed a bunch of different files that are used to define the sepolicy. .te files are used either to define type , or rules; file_contexts are used to label the resources. Those are all human readable files, for obvious reason. And, not surprise, a binary representation will be generated from those file for efficiency. Among the binary files, two important ones are sepolicy(.bin) and file_contexts.bin, which are all end up in the root file system during the build process. And they will be used by selinux to enforce the rules.
The seplicy(.bin) is the output of checkpolicy, with an intermediate file called policy.conf as the input. In turn, the policy.conf is an aggregation of all the *.tefiles, among others. And, a good news is that policy.conf is text based, so we can diff that to diagnose policy issues between two version change.
Apart from the sepolicy.bin and file_contexts.in, there are a few other files will be installed in either the rootfs or system partition during the build process, such as seapp_contexts, service_contexts and mac_permissions.xml. But we won't go details in this tutorial.

init and selinux in kernel

We have all the labels and rules in place but we haven't really set up anything yet. Say, apply a lable for a file. That is taken care by the init program.
Apart from the well know functionality such as read the init.rc, mount the partitions, and start the services, init also responsible for the initiation of selinux. It includes set up the labels for all the files according to the file_contexts.bin and pass the sepolicy to the kernel, among other things. Grep selinux_ in system/core/init/init.cpp for all the glory details.
How the selinux policy is actually enforced by the kernel is outside of the scope of this tutorial, but at least make sure the relevant configuration is enabled.

Summary

In this article, we start with why SELinux is introduced and the core idea of it - label every things, default denial, and explicit rules to allow anything. Then we look at the various components and steps need to implementation that stragey, in Android.
Hopefully at the end of the introduction, you are convinced that SELinux is a very effective way, if not the most effective way, to protect the device security. And I think SELinux should be mandatory on all the devices, be it mobile devices, IoT devices or servers. Of course, that mean they have to run Linux first, which is nice :)
For other stuffs such as enable/disable SElinux, how to interpret and fix the SELinux warning (svc message), you can check this official documentation.

A Hands-on of Android Things on Rpi3

Get a Rpi3 and follow the steps to flash the boot image to a SD card. Then, you are ready to explore.
I first hooked the HDMI output to my TV but the display is messy. But you can tell there is something on the screen, which is good sign that Android is running. Looks like the image stride is not correct. Probably the resolution doesn't match, e,g 1366x768 vs 1920x1080. I didn't dig further since I haven't get the adb working, yet.
It turned out adb over usb didn't work and the micro usb is for power only. So to get the adb, you have to connect the Ethernet cable (even you are very reluctant to do so as me) first and use adb over tcp.
$ adb devices
List of devices attached

$ adb connect Android.local
connected to Android.local:5555

$ adb devices
List of devices attached
Android.local:5555  device

$ adb shell
rpi3:/ $ 

As I said, I hate Ethernet, because I have no easy access to the Ethernet in my home office. So I want to set up the Wifi and use adb over it.
And, the doc says
Connect an Ethernet cable to your local network.
Note: You may also choose to connect over Wi-Fi.
That is misleanding, IMO. It sounds to me  you can use either Ethernet or Wifi. But, to connect to Wifi you should use adb shell commands, which means you have to connect to Ethernet first and then use adb command to connect to Wifi. The command provided works well. At least by checking the ifconfig output, wlan was assigned an IP address.
But doc here also says:
Network: Wi-Fi cannot connect to the internet if Ethernet is also connected to a network without internet access.
I have no idea what does that mean, especial the last few words.
As said, my purpose is to use the adb over Wifi, so I tried following steps but seems no luck. Maybe I messed up some steps or just didn't try enough times :)
1. Connect Ethernet
2. Connect adb over Ethernet
3. Setup Wifi using adb
4. Disconnect Ethernet
5. Reset the board and hope the Wifi will connect automatically
6. Connect adb over Wifi
With adb working, I can just dump a few things such as Partitions, Processes, Services and a few others. And, here are the (boring) dumps.

Partitions

A/B partition in place. Which is a mandatory feature for IoT device for effective seamless update.
rpi3:/ $ ls /dev/block/platform/soc/3f202000.sdhost/by-name/ -l                
total 0
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 boot_a -> /dev/block/mmcblk0p4
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 boot_b -> /dev/block/mmcblk0p5
lrwxrwxrwx 1 root root 21 1970-01-01 00:00 gapps_a -> /dev/block/mmcblk0p13
lrwxrwxrwx 1 root root 21 1970-01-01 00:00 gapps_b -> /dev/block/mmcblk0p14
lrwxrwxrwx 1 root root 21 1970-01-01 00:00 misc -> /dev/block/mmcblk0p10
lrwxrwxrwx 1 root root 21 1970-01-01 00:00 oem_a -> /dev/block/mmcblk0p11
lrwxrwxrwx 1 root root 21 1970-01-01 00:00 oem_b -> /dev/block/mmcblk0p12
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 rpiboot -> /dev/block/mmcblk0p1
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 system_a -> /dev/block/mmcblk0p6
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 system_b -> /dev/block/mmcblk0p7
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 uboot_a -> /dev/block/mmcblk0p2
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 uboot_b -> /dev/block/mmcblk0p3
lrwxrwxrwx 1 root root 21 1970-01-01 00:00 userdata -> /dev/block/mmcblk0p15
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 vbmeta_a -> /dev/block/mmcblk0p8
lrwxrwxrwx 1 root root 20 1970-01-01 00:00 vbmeta_b -> /dev/block/mmcblk0p9

Process

Notes: no Weaved, no Webserved.
USER      PID   PPID  VSIZE  RSS   WCHAN            PC  NAME
root      1     0     7336   1548           /init
root      2     0     0      0              kthreadd
root      3     2     0      0              ksoftirqd/0
root      5     2     0      0              kworker/0:0H
root      7     2     0      0              rcu_preempt
root      8     2     0      0              rcu_sched
root      9     2     0      0              rcu_bh
root      10    2     0      0              migration/0
root      11    2     0      0              migration/1
root      12    2     0      0              ksoftirqd/1
root      14    2     0      0              kworker/1:0H
root      15    2     0      0              migration/2
root      16    2     0      0              ksoftirqd/2
root      17    2     0      0              kworker/2:0
root      18    2     0      0              kworker/2:0H
root      19    2     0      0              migration/3
root      20    2     0      0              ksoftirqd/3
root      21    2     0      0              kworker/3:0
root      22    2     0      0              kworker/3:0H
root      23    2     0      0              kdevtmpfs
root      24    2     0      0              netns
root      25    2     0      0              perf
root      26    2     0      0              khungtaskd
root      27    2     0      0              writeback
root      28    2     0      0              ksmd
root      29    2     0      0              crypto
root      30    2     0      0              bioset
root      31    2     0      0              kblockd
root      33    2     0      0              cfg80211
root      34    2     0      0              rpciod
root      35    2     0      0              kswapd0
root      36    2     0      0              vmstat
root      37    2     0      0              fsnotify_mark
root      38    2     0      0              nfsiod
root      64    2     0      0              kthrotld
root      65    2     0      0              bioset
root      89    2     0      0              VCHIQ-0
root      90    2     0      0              VCHIQr-0
root      91    2     0      0              VCHIQs-0
root      92    2     0      0              iscsi_eh
root      93    2     0      0              spi0
root      94    2     0      0              dwc_otg
root      95    2     0      0              DWC Notificatio
root      96    2     0      0              VCHIQka-0
root      97    2     0      0              dm_bufio_cache
root      98    2     0      0              kworker/u8:1
root      99    2     0      0              irq/92-mmc1
root      100   2     0      0              bioset
root      101   2     0      0              mmcqd/0
root      102   2     0      0              binder
root      103   2     0      0              kworker/1:1
root      104   2     0      0              ipv6_addrconf
root      105   2     0      0              SMIO
root      106   2     0      0              deferwq
root      108   2     0      0              kworker/0:2
root      109   2     0      0              brcmf_wq/mmc1:0
root      110   2     0      0              brcmf_wdog/mmc1
root      114   2     0      0              jbd2/mmcblk0p6-
root      115   2     0      0              ext4-rsv-conver
root      116   1     2932   1132           /sbin/ueventd
root      121   2     0      0              jbd2/mmcblk0p15
root      122   2     0      0              ext4-rsv-conver
root      123   2     0      0              jbd2/mmcblk0p11
root      124   2     0      0              ext4-rsv-conver
root      125   2     0      0              jbd2/mmcblk0p13
root      126   2     0      0              ext4-rsv-conver
logd      127   1     11676  2700           /system/bin/logd
root      128   1     5344   2208           /system/bin/debuggerd
root      129   1     11784  4632           /system/bin/vold
root      134   2     0      0              kauditd
root      137   128   5088   508            debuggerd:signaller
root      145   1     2992   496            /sbin/healthd
root      146   1     4560   2412           /system/bin/lmkd
system    147   1     4600   1928           /system/bin/servicemanager
system    148   1     30480  12760          /system/bin/surfaceflinger
shell     150   1     9272   820            /sbin/adbd
root      151   1     965944 94544          zygote
audioserver 153   1     21844  7644         /system/bin/audioserver
cameraserver 154   1     14512  6516        /system/bin/cameraserver
drm       155   1     13316  5876           /system/bin/drmserver
root      156   1     4972   2052           /system/bin/installd
keystore  157   1     7476   3624           /system/bin/keystore
mediacodec 158   1     12968  5668          media.codec
media     159   1     17108  7672           /system/bin/mediadrmserver
mediaex   160   1     37784  7056           media.extractor
media     161   1     39664  9588           /system/bin/mediaserver
root      162   1     24916  3892           /system/bin/netd
root      163   1     9016   3948           /system/bin/peripheralman
root      165   1     3540   1876           /system/bin/sh
system    166   1     7236   2780           /system/bin/gatekeeperd
system    167   1     7060   3768           /system/bin/userinputdriverservice
metrics_coll 168   1     9152   4752        /system/bin/metrics_collector
metricsd  169   1     10868  4888           /system/bin/metricsd
root      175   1     4100   1876           /system/xbin/perfprofd
root      176   1     10072  6028           /system/bin/update_engine
mdnsr     179   1     2004   688            /system/bin/mdnsd
system    410   151   1088328 124132        /system_server
media_rw  479   129   8236   2668           /system/bin/sdcard
wifi      517   1     7572   3932           /system/bin/wpa_supplicant
system    541   151   1069296 72760         com.android.settings
u0_a5     571   151   1037892 57084         android.ext.services
u0_a4     599   151   1044800 70048         android.process.media
system    618   151   1045744 71300         com.android.iotlauncher
u0_a7     643   151   1179200 92776         com.google.android.gms.feedback
u0_a7     658   151   1213404 147912        com.google.android.gms.persistent
u0_a8     684   151   1039576 57448         com.android.managedprovisioning
u0_a9     698   151   1037816 56488         com.android.onetimeinitializer
u0_a1     715   151   1040192 64552         com.android.providers.calendar
u0_a7     730   151   1051700 71176         com.google.process.gapps
u0_a7     772   151   1333476 156352        com.google.android.gms
radio     864   151   1040476 62692         com.android.phone
u0_a2     896   151   1047240 73176         android.process.acore
u0_a7     949   151   1179200 94860         com.google.android.gms.ui

Services

Found 110 services:
0   gpsdriverservice: [com.google.android.things.userdriver.IGpsDriverService]
1   contexthub_service: [android.hardware.location.IContextHubService]
2   dns_listener: [android.net.metrics.IDnsEventListener]
3   connectivity_metrics_logger: [android.net.IConnectivityMetricsLogger]
4   imms: [com.android.internal.telephony.IMms]
5   media_projection: [android.media.projection.IMediaProjectionManager]
6   launcherapps: [android.content.pm.ILauncherApps]
7   shortcut: [android.content.pm.IShortcutService]
8   trust: [android.app.trust.ITrustManager]
9   media_router: [android.media.IMediaRouterService]
10  media_session: [android.media.session.ISessionManager]
11  restrictions: [android.content.IRestrictionsManager]
12  graphicsstats: [android.view.IGraphicsStats]
13  assetatlas: [android.view.IAssetAtlas]
14  dreams: [android.service.dreams.IDreamManager]
15  commontime_management: []
16  network_time_update_service: []
17  samplingprofiler: []
18  diskstats: []
19  appwidget: [com.android.internal.appwidget.IAppWidgetService]
20  soundtrigger: [com.android.internal.app.ISoundTriggerService]
21  jobscheduler: [android.app.job.IJobScheduler]
22  hardware_properties: [android.os.IHardwarePropertiesManager]
23  serial: [android.hardware.ISerialManager]
24  DockObserver: []
25  audio: [android.media.IAudioService]
26  wallpaper: [android.app.IWallpaperManager]
27  dropbox: [com.android.internal.os.IDropBoxManagerService]
28  search: [android.app.ISearchManager]
29  country_detector: [android.location.ICountryDetector]
30  location: [android.location.ILocationManager]
31  devicestoragemonitor: []
32  notification: [android.app.INotificationManager]
33  recovery: [android.os.IRecoverySystem]
34  updatelock: [android.os.IUpdateLock]
35  servicediscovery: [android.net.nsd.INsdManager]
36  connectivity: [android.net.IConnectivityManager]
37  ethernet: [android.net.IEthernetManager]
38  rttmanager: [android.net.wifi.IRttManager]
39  wifiscanner: [android.net.wifi.IWifiScanner]
40  wifi: [android.net.wifi.IWifiManager]
41  wifip2p: [android.net.wifi.p2p.IWifiP2pManager]
42  netpolicy: [android.net.INetworkPolicyManager]
43  netstats: [android.net.INetworkStatsService]
44  network_score: [android.net.INetworkScoreService]
45  textservices: [com.android.internal.textservice.ITextServicesManager]
46  network_management: [android.os.INetworkManagementService]
47  clipboard: [android.content.IClipboard]
48  statusbar: [com.android.internal.statusbar.IStatusBarService]
49  device_policy: [android.app.admin.IDevicePolicyManager]
50  deviceidle: [android.os.IDeviceIdleController]
51  lock_settings: [com.android.internal.widget.ILockSettings]
52  uimode: [android.app.IUiModeManager]
53  mount: [IMountService]
54  accessibility: [android.view.accessibility.IAccessibilityManager]
55  input_method: [com.android.internal.view.IInputMethodManager]
56  pinner: []
57  vrmanager: [android.service.vr.IVrManager]
58  input: [android.hardware.input.IInputManager]
59  window: [android.view.IWindowManager]
60  alarm: [android.app.IAlarmManager]
61  consumer_ir: [android.hardware.IConsumerIrService]
62  vibrator: [android.os.IVibratorService]
63  content: [android.content.IContentService]
64  account: [android.accounts.IAccountManager]
65  media.camera.proxy: [android.hardware.ICameraServiceProxy]
66  telephony.registry: [com.android.internal.telephony.ITelephonyRegistry]
67  scheduling_policy: [android.os.ISchedulingPolicyService]
68  webviewupdate: [android.webkit.IWebViewUpdateService]
69  usagestats: [android.app.usage.IUsageStatsManager]
70  battery: []
71  sensorservice: [android.gui.SensorServer]
72  sensordriverservice: [com.google.android.things.userdriver.ISensorDriverService]
73  processinfo: [android.os.IProcessInfoService]
74  permission: [android.os.IPermissionController]
75  cpuinfo: []
76  dbinfo: []
77  gfxinfo: []
78  meminfo: []
79  procstats: [com.android.internal.app.procstats.IProcessStats]
80  activity: [android.app.IActivityManager]
81  user: [android.os.IUserManager]
82  otadexopt: [android.content.pm.IOtaDexopt]
83  package: [android.content.pm.IPackageManager]
84  display: [android.hardware.display.IDisplayManager]
85  power: [android.os.IPowerManager]
86  appops: [com.android.internal.app.IAppOpsService]
87  batterystats: [com.android.internal.app.IBatteryStats]
88  netd: [android.net.INetd]
89  media.camera: [android.hardware.ICameraService]
90  media.drm: [android.media.IMediaDrmService]
91  media.resource_manager: [android.media.IResourceManagerService]
92  media.player: [android.media.IMediaPlayerService]
93  media.extractor: [android.media.IMediaExtractorService]
94  media.sound_trigger_hw: [android.hardware.ISoundTriggerHwService]
95  media.radio: [android.hardware.IRadioService]
96  media.audio_policy: [android.media.IAudioPolicyService]
97  media.audio_flinger: [android.media.IAudioFlinger]
98  drm.drmManager: [drm.IDrmManagerService]
99  media.codec: [android.media.IMediaCodecService]
100 android.brillo.UpdateEngineService: [android.brillo.IUpdateEngine]
101 android.brillo.metrics.IMetricsCollectorService: [android.brillo.metrics.IMetricsCollectorService]
102 gpu: [android.ui.IGpuService]
103 SurfaceFlinger: [android.ui.ISurfaceComposer]
104 batteryproperties: [android.os.IBatteryPropertiesRegistrar]
105 android.brillo.metrics.IMetricsd: [android.brillo.metrics.IMetricsd]
106 com.google.android.things.pio.IPeripheralManager: [com.google.android.things.pio.IPeripheralManager]
107 inputdriverservice: [com.google.android.things.userdriver.IInputDriverService]
108 android.security.keystore: [android.security.IKeystoreService]
109 android.service.gatekeeper.IGateKeeperService: [android.service.gatekeeper.IGateKeeperService]

Things/Brillo specific services

0   gpsdriverservice: [com.google.android.things.userdriver.IGpsDriverService]
72  sensordriverservice: [com.google.android.things.userdriver.ISensorDriverService]
106 com.google.android.things.pio.IPeripheralManager: [com.google.android.things.pio.IPeripheralManager]
107 inputdriverservice: [com.google.android.things.userdriver.IInputDriverService]

100 android.brillo.UpdateEngineService: [android.brillo.IUpdateEngine]
101 android.brillo.metrics.IMetricsCollectorService: [android.brillo.metrics.IMetricsCollectorService]
105 android.brillo.metrics.IMetricsd: [android.brillo.metrics.IMetricsd]

props

rpi3:/ $ getprop                                                               
[camera.disable_zsl_mode]: [1]
[crash_reporter.coredump.enabled]: [1]
[dalvik.vm.appimageformat]: [lz4]
[dalvik.vm.dex2oat-Xms]: [64m]
[dalvik.vm.dex2oat-Xmx]: [512m]
[dalvik.vm.heapsize]: [256m]
[dalvik.vm.image-dex2oat-Xms]: [64m]
[dalvik.vm.image-dex2oat-Xmx]: [64m]
[dalvik.vm.isa.arm.features]: [default]
[dalvik.vm.isa.arm.variant]: [generic]
[dalvik.vm.lockprof.threshold]: [500]
[dalvik.vm.stack-trace-file]: [/data/anr/traces.txt]
[dalvik.vm.usejit]: [true]
[dalvik.vm.usejitprofiles]: [true]
[debug.atrace.tags.enableflags]: [0]
[debug.force_rtl]: [0]
[dev.bootcomplete]: [1]
[init.svc.adbd]: [running]
[init.svc.audioserver]: [running]
[init.svc.bootanim]: [stopped]
[init.svc.cameraserver]: [running]
[init.svc.console]: [running]
[init.svc.crash_reporter]: [stopped]
[init.svc.crash_sender]: [running]
[init.svc.debuggerd]: [running]
[init.svc.drm]: [running]
[init.svc.gatekeeperd]: [running]
[init.svc.healthd]: [running]
[init.svc.inputdriverserv]: [running]
[init.svc.installd]: [running]
[init.svc.keystore]: [running]
[init.svc.lmkd]: [running]
[init.svc.logd]: [running]
[init.svc.logd-reinit]: [stopped]
[init.svc.mdnsd]: [running]
[init.svc.media]: [running]
[init.svc.mediacodec]: [running]
[init.svc.mediadrm]: [running]
[init.svc.mediaextractor]: [running]
[init.svc.metricscollector]: [running]
[init.svc.metricsd]: [running]
[init.svc.netd]: [running]
[init.svc.perfprofd]: [running]
[init.svc.peripheralman]: [running]
[init.svc.servicemanager]: [running]
[init.svc.surfaceflinger]: [running]
[init.svc.ueventd]: [running]
[init.svc.update_engine]: [running]
[init.svc.vold]: [running]
[init.svc.wpa_supplicant]: [running]
[init.svc.zygote]: [running]
[log.tag.Hyphenator]: [SUPPRESS]
[log.tag.WifiHAL]: [D]
[net.bt.name]: [Android]
[net.change]: [net.dns3]
[net.dns1]: [211.29.132.12]
[net.dns2]: [198.142.0.51]
[net.dns3]: [198.142.235.14]
[net.hostname]: [android-226a3ebfc34ad1f3]
[net.qtaguid_enabled]: [1]
[net.tcp.default_init_rwnd]: [60]
[persist.sys.dalvik.vm.lib.2]: [libart.so]
[persist.sys.profiler_ms]: [0]
[persist.sys.usb.config]: [adb]
[persist.sys.webview.vmsize]: [104857600]
[pm.dexopt.ab-ota]: [speed-profile]
[pm.dexopt.bg-dexopt]: [speed-profile]
[pm.dexopt.boot]: [verify-profile]
[pm.dexopt.core-app]: [speed]
[pm.dexopt.first-boot]: [interpret-only]
[pm.dexopt.forced-dexopt]: [speed]
[pm.dexopt.install]: [interpret-only]
[pm.dexopt.nsys-library]: [speed]
[pm.dexopt.shared-apk]: [speed]
[qemu.gles]: [-1]
[ro.allow.mock.location]: [0]
[ro.baseband]: [unknown]
[ro.board.platform]: []
[ro.boot.hardware]: [rpi3]
[ro.boot.selinux]: [permissive]
[ro.boot.slot_suffix]: [_a]
[ro.bootimage.build.date]: [Mon Dec 12 20:53:57 UTC 2016]
[ro.bootimage.build.date.utc]: [1481576037]
[ro.bootimage.build.fingerprint]: [generic/iot_rpi3/rpi3:7.0/NIF73/3565696:userdebug/test-keys]
[ro.bootloader]: [unknown]
[ro.bootmode]: [unknown]
[ro.build.ab_update]: [true]
[ro.build.characteristics]: [default]
[ro.build.date]: [Mon Dec 12 20:53:57 UTC 2016]
[ro.build.date.utc]: [1481576037]
[ro.build.description]: [iot_rpi3-userdebug 7.0 NIF73 3565696 test-keys]
[ro.build.display.id]: [iot_rpi3-userdebug 7.0 NIF73 3565696 test-keys]
[ro.build.fingerprint]: [generic/iot_rpi3/rpi3:7.0/NIF73/3565696:userdebug/test-keys]
[ro.build.flavor]: [iot_rpi3-userdebug]
[ro.build.host]: [vpeb11.mtv.corp.google.com]
[ro.build.id]: [NIF73]
[ro.build.product]: [rpi3]
[ro.build.system_root_image]: [true]
[ro.build.tags]: [test-keys]
[ro.build.type]: [userdebug]
[ro.build.user]: [android-build]
[ro.build.version.all_codenames]: [REL]
[ro.build.version.base_os]: []
[ro.build.version.codename]: [REL]
[ro.build.version.incremental]: [3565696]
[ro.build.version.preview_sdk]: [0]
[ro.build.version.release]: [7.0]
[ro.build.version.sdk]: [24]
[ro.build.version.security_patch]: [2016-12-05]
[ro.carrier]: [unknown]
[ro.config.alarm_alert]: [Alarm_Classic.ogg]
[ro.config.notification_sound]: [OnTheHunt.ogg]
[ro.crypto.state]: [unsupported]
[ro.dalvik.vm.native.bridge]: [0]
[ro.debuggable]: [1]
[ro.hardware]: [rpi3]
[ro.hardware.camera]: [v4l2]
[ro.hardware.gps]: [iot]
[ro.hardware.sensors]: [iot]
[ro.kernel.qemu]: [1]
[ro.kernel.qemu.force_gles]: [-1]
[ro.product.board]: [rpi3]
[ro.product.brand]: [generic]
[ro.product.cpu.abi]: [armeabi-v7a]
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abilist]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: []
[ro.product.device]: [rpi3]
[ro.product.manufacturer]: [unknown]
[ro.product.model]: [iot_rpi3]
[ro.product.name]: [iot_rpi3]
[ro.revision]: [0]
[ro.runtime.firstboot]: [59481]
[ro.secure]: [1]
[ro.serialno]: []
[ro.wifi.channels]: []
[ro.zygote]: [zygote32]
[security.perf_harden]: [1]
[selinux.reload_policy]: [1]
[service.bootanim.exit]: [1]
[sys.boot_completed]: [1]
[sys.sysctl.extra_free_kbytes]: [12294]
[sys.sysctl.tcp_def_init_rwnd]: [60]
[sys.usb.config]: [adb]
[sys.usb.configfs]: [0]
[sys.usb.state]: [adb]
[vold.has_adoptable]: [0]
[wifi.interface]: [wlan0]
[wifi.supplicant_scan_interval]: [15]
[wlan.driver.status]: [ok]

Graphic/Display

Only one layer, a full screen iotlauncher. Built-in screen is 1366x768.
$ dumpsys SurfaceFlinger
Build configuration: [sf] [libui] [libgui]
Sync configuration: [using: EGL_KHR_fence_sync]

Visible layers (count = 1)
+ Layer 0xb11dc400 (com.android.iotlauncher/com.android.iotlauncher.IoTLauncher)

Displays (1 entries)
+ DisplayDevice: Built-in Screen
   type=0, hwcId=0, layerStack=0, (1366x 768), ANativeWindow=0xb08aa008, orient= 0 (type=00000000), flips=1254, isSecure=1, powerMode=2, activeConfig=0, numLayers=1
   v:[0,0,1366,768], f:[0,0,1366,768], s:[0,0,1366,768],transform:[[1.000,0.000,-0.000][0.000,1.000,-0.000][0.000,0.000,1.000]]

SurfaceFlinger global state:
EGL implementation : 1.2 Android Driver 1.2.0
EGL_KHR_fence_sync EGL_KHR_image_base EGL_ANDROID_image_native_buffer EGL_ANDROID_swap_rectangle 
GLES: Android, Android PixelFlinger 1.4, OpenGL ES-CM 1.0
GL_EXT_debug_marker GL_OES_byte_coordinates GL_OES_fixed_point GL_OES_single_precision GL_OES_read_format GL_OES_compressed_paletted_texture GL_OES_draw_texture GL_OES_matrix_get GL_OES_query_matrix GL_OES_EGL_image GL_OES_EGL_sync GL_OES_compressed_ETC1_RGB8_texture GL_ARB_texture_compression GL_ARB_texture_non_power_of_two GL_ANDROID_user_clip_plane GL_ANDROID_vertex_buffer_object GL_ANDROID_generate_mipmap 
  Region undefinedRegion (this=0xb11f82ac, count=1)
    [  0,   0,   0,   0]
  orientation=0, isDisplayOn=1
  last eglSwapBuffers() time: 21.146000 us
  last transaction time     : 33.385000 us
  transaction-flags         : 00000000
  refresh-rate              : 60.000002 fps
  x-dpi                     : 159.891235
  y-dpi                     : 159.895081
  gpu_to_cpu_unsupported    : 0
  eglSwapBuffers time: 0.000000 us
  transaction time: 0.000000 us
h/w composer state:
  h/w composer not present and enabled
Allocated buffers:
0xb0e1a2c0: 4098.00 KiB | 1366 (1366) x  768 |        1 | 0x00000933
0xb1197340: 2049.00 KiB | 1366 (1366) x  768 |        4 | 0x00001a33
0xb1197440: 2049.00 KiB | 1366 (1366) x  768 |        4 | 0x00001a33
0xb1197900: 4098.00 KiB | 1366 (1366) x  768 |        1 | 0x00000933
Total allocated (estimate): 12294.00 KB

Camera

Used v4l2 camera HAL. Obviously, it means the camera support is not complete since the standard v4l2 interfaces aren't sufficient to support a full Android camera v3. This was one of the problem Project Ara team tried to solve and there are some relevant discussion ongoing in the v4l2 kernel community.
$ dumpsys media.camera
Camera module HAL API version: 0x100
Camera module API version: 0x204
Camera module name: V4L2 Camera HAL v3
Camera module author: The Android Open Source Project
Number of camera devices: 0
Number of normal camera devices: 0