Skip to content

Commit

Permalink
Added post about removing a device feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Florian Bramer committed Aug 11, 2023
1 parent 77d52be commit 3e9b1b1
Showing 1 changed file with 131 additions and 0 deletions.
131 changes: 131 additions & 0 deletions content/posts/remove-device-feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
title: "How to remove a Device Feature"
date: 2023-08-07T13:12:43+02:00
draft: false
author: "Florian Bramer"
---

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.

### Inspect 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>
```

### Remove 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.

0 comments on commit 3e9b1b1

Please sign in to comment.