Skip to content

Instantly share code, notes, and snippets.

@tniessen
Created October 1, 2016 11:46
Show Gist options
  • Save tniessen/ea3d68e7d572ed7c607b81d715798800 to your computer and use it in GitHub Desktop.
Save tniessen/ea3d68e7d572ed7c607b81d715798800 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.

@dpacmittal
Copy link

Thanks a lot! This helped me mute a phone with broken screen blasting my morning alarm since last 5 hours.

@sundayz
Copy link

sundayz commented Jun 4, 2019

When trying to get the IMEI of a phone through adb's shell service call I thought the output was malformed. But nope, looks like adb is perfectly happy returning hex data as a string, in a format that's not easy to parse. Great.

Good write up, takes forever to find documentation about this stuff.

@pkeno
Copy link

pkeno commented Mar 5, 2024

Usage of the service call, whith possible paramaters:

Usage: service [-h|-?]
       service list
       service check SERVICE
       service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null | fd f | nfd n | afd f ] ...
Options:
   i32: Write the 32-bit integer N into the send parcel.
   i64: Write the 64-bit integer N into the send parcel.
     f: Write the 32-bit single-precision number N into the send parcel.
     d: Write the 64-bit double-precision number N into the send parcel.
   s16: Write the UTF-16 string STR into the send parcel.
  null: Write a null binder into the send parcel.
    fd: Write a file descriptor for the file f into the send parcel.
   nfd: Write the file descriptor n into the send parcel.
   afd: Write an ashmem file descriptor for a region containing the data from
          file f into the send parcel.

(https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/native/cmds/service/service.cpp)

@dmitryuk
Copy link

service call only for system services. How to call IBinder methods for non-system's one using adb ?

Example Java code I need to translate to ADB:

Parcel obtain = Parcel.obtain();
                Parcel obtain2 = Parcel.obtain();
                try {
                    obtain.writeInterfaceToken(IOp.DESCRIPTOR);
                    obtain.writeInt(z ? 1 : 0);
                    this.mRemote.transact(6, obtain, obtain2, 0)

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