Recently, I had to remove a couple of device features from an Android 12 build.

Some reasons why we wanted to remove them:

  • they were actually not supported by our device
  • we didn’t want to expose them to the user
  • they were causing unnecessary CTS failures

In this post, I want to guide you through the steps I took to trim down the list of declared device features.

What are Device Features?

Any android devices declares a list of device features it supports. For example, in the early years of Android, there where phones with and without a built in compass sensor.

Imagine you are an app developer working on a compass app and you want to assure that your app only gets installed on phones with compass sensor.

You could archive that by declaring a dependency onto the corresponding device feature in your AndroidManifest.xml:

<manifest ... >
    <uses-feature android:name="android.hardware.sensor.compass"
                  android:required="true" />
    ...
</manifest>

See https://developer.android.com/guide/topics/manifest/uses-feature-element#features-reference for a list of device features.

Inspecting all exposed Device Features

First let’s inspect all the device features our device declares. One can do that by using an adb shell session and Android’s package manager.

> pm list features
feature:android.hardware.audio.output
feature:android.hardware.bluetooth
feature:android.hardware.bluetooth_le
feature:android.hardware.broadcastradio
feature:android.hardware.camera.any
feature:android.hardware.camera.autofocus
feature:android.hardware.ethernet
feature:android.hardware.faketouch
feature:android.hardware.location
feature:android.hardware.location.gps
feature:android.hardware.location.network
...
<many more>
...

Let’s take a deeper look how this list is assembled.

The package manager calculates the list from the .xml files it can find in the these folders

  • vendor/etc/permissions
  • system/etc/permissions
  • system_ext/etc/permissions

during startup. For example at

vendor/etc/permissions/android.hardware.bluetooth_le.xml

we can find the file which declares the android.hardware.bluetooth_le device feature we saw in the list above:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<!-- Adds the feature indicating support for the Bluetooth Low Energy API -->
<permissions>
    <feature name="android.hardware.bluetooth_le" />
</permissions>

Removing individual Device Features

Now let’s imagine we would like to remove android.hardware.bluetooth_le from the list of declared device features. An obvious way to do that, would be to find the android.hardware.bluetooth_le.xml file in our source tree and remove (or comment out) the line which defines the feature:

frameworks/native/data/etc/android.hardware.bluetooth_le.xml:

<permissions>
<!--
    Purposly commented out because we don't want to support BT Low Energy on our device
    <feature name="android.hardware.bluetooth_le" />
-->
</permissions>

But this solution comes with a couple of drawbacks:

  • By AOSP convention, individual device configurations should go into the device/ folder. Your co-workers might not find this change if you place it underneath frameworks/native
  • Once a new Android version gets introduced into the project, your change might get overwritten

A more sustainable way to trim the list of device features would be to introduce a new .xml file in the device folder of your device.

e.g. unavailable-features.xml:

<?xml version="1.0" encoding="utf-8"?>

<permissions>
    <!-- we don't want to support BT Low Energy on our device -->
    <unavailable-feature name="android.hardware.bluetooth_le" />
</permissions>

All you need to do then is to copy the .xml during built time onto the vendor partition in one of your .mk files:

PRODUCT_COPY_FILES += device/<vendor>/<device>/unavailable-features.xml:vendor/etc/permissions/unavailable-features.xml

Afterwards the package manager will include your .xml into his calculations and android.hardware.bluetooth_le will disappear from the list of declared device features.