Skip to content

Instantly share code, notes, and snippets.

@qwIvan
Forked from tniessen/service.md
Created December 16, 2017 09:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qwIvan/d0e3df8d70604454a5ceccd4a64e9cc7 to your computer and use it in GitHub Desktop.
Save qwIvan/d0e3df8d70604454a5ceccd4a64e9cc7 to your computer and use it in GitHub Desktop.
Using the "service" tool with ADB and why to avoid it

As it turns out, it is not trivial to control the audio volume of an Android device using ADB. At the time of writing, the only way appears to be using the service tool. Actually, the service command allows to "connect" to a number of services (104 on Android 6.0.1) and invoke functions. Not knowing much about this tool, I managed to completely mute all sounds and speakers of my Nexus 5, and I was stuck without any sound for quite some time. I did not find a way to unmute the sound from within the system UI, so I got to dive a little deeper into this.

If you know which service you want to use, you then need to find its interface declaration. The command

service list

gives you a list of all services with the associated interfaces, if applicable:

...
26      backup: [android.app.backup.IBackupManager]
27      jobscheduler: [android.app.job.IJobScheduler]
28      serial: [android.hardware.ISerialManager]
29      usb: [android.hardware.usb.IUsbManager]
30      midi: [android.media.midi.IMidiManager]
31      DockObserver: []
32      audio: [android.media.IAudioService]
33      wallpaper: [android.app.IWallpaperManager]
34      dropbox: [com.android.internal.os.IDropBoxManagerService]
35      search: [android.app.ISearchManager]
36      country_detector: [android.location.ICountryDetector]
37      location: [android.location.ILocationManager]
38      devicestoragemonitor: []
...

For me, the audio service was relevant, which appeared at index 32. The associated interface is android.media.IAudioService, so the next thing you will want to do is find the source code of that file. And, even more importantly, find the correct version of that file (this was my mistake in the first place). For 6.0.1, you can find the interface declaration here. If you select a different branch on GitHub, you will see that the file differs from release to release.

In order to call a function of the interface, we need to know its index in the interface declaration. For example, to mute all sound, I will use IAudioService.setMasterMute. This function is the 8th method in the interface declaration. We will need this index soon, and it appears to start with 1 (so the first function has the index 1, not 0!). Additionally, we need to supply the correct arguments to the function. The declaration looks like this:

void setMasterMute(boolean mute, int flags, String callingPackage, int userId);

We will only supply the first two arguments, which are a boolean and an integer, which are both treated as integers for now.

In the ADB shell, the command

service call audio 8 i32 1 i32 0

mutes all sounds on my Nexus 5 (6.0.1). service call audio is self explanatory, 8 is the function index, i32 1 represents the boolean value true and i32 0 represents the integer 0 for the flags parameter.

We can use the function IAudioService.isMasterMute to verify the result (or you could just try to make a call or watch a video, you should hear nothing, no matter what you set your volume to). Its signature is simple:

boolean isMasterMute();

It is the 7th function in the interface, so we can call it using

service call audio 7

After issuing the command, it should output something like

shell@hammerhead:/ $ service call audio 7
Result: Parcel(00000000 00000001   '........')

Note that the last digit is set to 1, and as isMasterMute() should return a boolean, we interpret this as true.

Unmuting is as simple as muting the device:

service call audio 8 i32 0 i32 0

Again, use isMasterMute() to verify the result:

shell@hammerhead:/ $ service call audio 7
Result: Parcel(00000000 00000000   '........')

All zeroes represent the value false, so the result is correct!

When to avoid using service

Basically, whenever possible. The command and the interfaces are documented poorly and they are subject to change from release to release. You can use the command for manual debugging (and that might be the reason it was developed), but if you intend to use it in scripting, you will eventually run into problems. You need to change the command for each release, possibly even depending on the device, and I have no idea how much CyanogenMod and friends care about such compatibility. Many features are available without using service, and if there is a better interface to it, use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment