3

For research purposes, I'm modifying Android SystemServer code.

What am I trying to accomplish?

Whenever there is a call to SystemServer (Binder server process), I want to know the source of this call on the Binder client process; more specifically - the source in my application (e.g., File, Class, Method, etc..).

For example, consider the following code from my app:

public class ClipboardReaderService extends Service {
    private ClipboardManager mClipboardManager;

    private ClipboardManager.OnPrimaryClipChangedListener mListener = 
            new ClipboardManager.OnPrimaryClipChangedListener() {
        @Override
        public void onPrimaryClipChanged() {
            String clipContent = mClipboardManager.getPrimaryClip().
                    getItemAt(0).getText().toString();
            Log.i(TAG, "Clipboard content: " + clipContent);
        }
    };

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mClipboardManager = (ClipboardManager) 
                getSystemService(CLIPBOARD_SERVICE);
        mClipboardManager.addPrimaryClipChangedListener(mListener);

        return START_STICKY;
    }
}

Using Binder, the corresponding function in SystemServer is being called (and this is where my code should go):

public ClipData getPrimaryClip(String pkg) {
    synchronized (this) {
        if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, 
                        Binder.getCallingUid(), pkg)
                        != AppOpsManager.MODE_ALLOWED || isDeviceLocked()) {
            return null;
        }

        // My code goes here - How can I get the caller method?

        addActiveOwnerLocked(Binder.getCallingUid(), pkg);
        return getClipboard().primaryClip;
    }
}

As I explained above, I have the ability to change the code in SystemServer, and I want to extract the origin of the call on the client side.

What i have tried so far?

So far, I've been trying to extract the client call stack because the information I want should be at the bottom of it.

  • Print the stack using Thread.currentThread().getStackTrace() - of course this doesn't work, since I print the SystemServer's stack, so I don't see the calls made on the clinet side.
  • Print stack traces for all live threads using getAllStackTraces() - Again, I can't see the client threads since they exist in a separate JVM.
  • Print the stack in ClipboardManager (i.e., in setPrimaryClip function) - It did print the client call stack as expected. In fact, I can pass the call stack as an additional parameter to SystemServer, but then I will have to do this for each function in each service (e.g., NotificationManager) and I'm looking for a more comprehensive solution.
  • Get the caller uid using Binder.getCallingPid() and read the stack from /proc/$pid/stack - That didn't work either, since /proc/$pid/stack only shows kernel stacks.
Aviad
  • 31
  • 3
  • Can you give more details? Are you just interested in logging debug information or do you want to do further processing with this information? If the latter, what would you want to happen when a Binder interface is called from a non-Java source, i.e. from C++ native code? – f9c69e9781fa194211448473495534 Aug 20 '19 at 09:05
  • @f9c69e9781fa194211448473495534 I'm just interested in logging the caller/client identity (class, method, file, etc..) – Aviad Aug 20 '19 at 09:12
  • So if there is a central place in the Android framework code where all Binder calls originating from Java code pass through on the client side, would it be acceptable to insert logging there, or does it have to take place on the server side? – f9c69e9781fa194211448473495534 Aug 20 '19 at 09:25
  • @f9c69e9781fa194211448473495534 On the server side. Although, if there is such a place that drains all the calls in the Android framework on the client side, I might use it (in case there is no other option). Can you Please elaborate on this? – Aviad Aug 20 '19 at 11:33
  • Check [BinderProxy#transact](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/BinderProxy.java#453), where all remote (i.e. non-thread-local) Binder calls from Java pass through. Also check the Java code auto-generated from the aidl specification, e.g. out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/content/IClipboard.java. – f9c69e9781fa194211448473495534 Aug 20 '19 at 11:50

0 Answers0