Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78ecd34d authored by Olivier Gaillard's avatar Olivier Gaillard Committed by Android (Google) Code Review
Browse files

Merge changes I02e88c93,Id0a2f52c

* changes:
  Use the BinderProxy#TransactListener to propagate the UID.
  Adds a mechanism to listen to proxy transact method calls.
parents 76992cc0 def1b90d
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -554,6 +554,79 @@ public class Binder implements IBinder {
        sDumpDisabled = msg;
    }

    /**
     * Listener to be notified about each proxy-side binder call.
     *
     * See {@link setProxyTransactListener}.
     * @hide
     */
    public interface ProxyTransactListener {
        /**
         * Called before onTransact.
         *
         * @return an object that will be passed back to #onTransactEnded (or null).
         */
        Object onTransactStarted(IBinder binder, int transactionCode);

        /**
         * Called after onTranact (even when an exception is thrown).
         *
         * @param session The object return by #onTransactStarted.
         */
        void onTransactEnded(@Nullable Object session);
    }

    /**
     * Propagates the work source to binder calls executed by the system server.
     *
     * <li>By default, this listener will propagate the worksource if the outgoing call happens on
     * the same thread as the incoming binder call.
     * <li>Custom attribution can be done by calling {@link ThreadLocalWorkSourceUid#set(int)}.
     * @hide
     */
    public static class PropagateWorkSourceTransactListener implements ProxyTransactListener {
        @Override
        public Object onTransactStarted(IBinder binder, int transactionCode) {
           // Note that {@link Binder#getCallingUid()} is already set to the UID of the current
           // process when this method is called.
           //
           // We use ThreadLocalWorkSourceUid instead. It also allows feature owners to set
           // {@link ThreadLocalWorkSourceUid#set(int) manually to attribute resources to a UID.
            int uid = ThreadLocalWorkSourceUid.get();
            if (uid >= 0) {
                int originalUid = Binder.setThreadWorkSource(uid);
                return Integer.valueOf(originalUid);
            }
            return null;
        }

        @Override
        public void onTransactEnded(Object session) {
            if (session != null) {
                int uid = (int) session;
                Binder.setThreadWorkSource(uid);
            }
        }
    }

    /**
     * Sets a listener for the transact method on the proxy-side.
     *
     * <li>The listener is global. Only fast operations should be done to avoid thread
     * contentions.
     * <li>The listener implementation needs to handle synchronization if needed. The methods on the
     * listener can be called concurrently.
     * <li>Listener set will be used for new transactions. On-going transaction will still use the
     * previous listener (if already set).
     * <li>The listener is called on the critical path of the binder transaction so be careful about
     * performance.
     * <li>Never execute another binder transaction inside the listener.
     * @hide
     */
    public static void setProxyTransactListener(@Nullable ProxyTransactListener listener) {
        BinderProxy.setTransactListener(listener);
    }

    /**
     * Default implementation is a stub that returns false.  You will want
     * to override this to do the appropriate unmarshalling of transactions.
+22 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.os;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
import android.util.SparseIntArray;

@@ -45,6 +46,15 @@ public final class BinderProxy implements IBinder {
    // Assume the process-wide default value when created
    volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking;

    private static volatile Binder.ProxyTransactListener sTransactListener = null;

    /**
     * @see {@link Binder#setProxyTransactListener(listener)}.
     */
    public static void setTransactListener(@Nullable Binder.ProxyTransactListener listener) {
        sTransactListener = listener;
    }

    /*
     * Map from longs to BinderProxy, retaining only a WeakReference to the BinderProxies.
     * We roll our own only because we need to lazily remove WeakReferences during accesses
@@ -469,9 +479,21 @@ public final class BinderProxy implements IBinder {
            Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
                    stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
        }

        // Make sure the listener won't change while processing a transaction.
        final Binder.ProxyTransactListener transactListener = sTransactListener;
        Object session = null;
        if (transactListener != null) {
            session = transactListener.onTransactStarted(this, code);
        }

        try {
            return transactNative(code, data, reply, flags);
        } finally {
            if (transactListener != null) {
                transactListener.onTransactEnded(session);
            }

            if (tracingEnabled) {
                Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
            }
+88 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

package android.os;

import android.annotation.Nullable;
import android.content.Context;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;

public class BinderProxyTest extends AndroidTestCase {
    private static class CountingListener implements Binder.ProxyTransactListener {
        int mStartedCount;
        int mEndedCount;

        public Object onTransactStarted(IBinder binder, int transactionCode) {
            mStartedCount++;
            return null;
        }

        public void onTransactEnded(@Nullable Object session) {
            mEndedCount++;
        }
    };

    private PowerManager mPowerManager;

    /**
     * Setup any common data for the upcoming tests.
     */
    @Override
    public void setUp() throws Exception {
        super.setUp();
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    }

    @MediumTest
    public void testNoListener() throws Exception {
        CountingListener listener = new CountingListener();
        Binder.setProxyTransactListener(listener);
        Binder.setProxyTransactListener(null);

        mPowerManager.isInteractive();

        assertEquals(0, listener.mStartedCount);
        assertEquals(0, listener.mEndedCount);
    }

    @MediumTest
    public void testListener() throws Exception {
        CountingListener listener = new CountingListener();
        Binder.setProxyTransactListener(listener);

        mPowerManager.isInteractive();

        assertEquals(1, listener.mStartedCount);
        assertEquals(1, listener.mEndedCount);
    }

    @MediumTest
    public void testSessionPropagated() throws Exception {
        Binder.setProxyTransactListener(new Binder.ProxyTransactListener() {
            public Object onTransactStarted(IBinder binder, int transactionCode) {
                return "foo";
            }

            public void onTransactEnded(@Nullable Object session) {
                assertEquals("foo", session);
            }
        });

        // Check it does not throw..
        mPowerManager.isInteractive();
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ public class BinderCallsStatsService extends Binder {
    private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
            = "persist.sys.binder_calls_detailed_tracking";


    /** Listens for flag changes. */
    private static class SettingsObserver extends ContentObserver {
        private static final String SETTINGS_ENABLED_KEY = "enabled";
@@ -101,7 +102,14 @@ public class BinderCallsStatsService extends Binder {
            final boolean enabled =
                    mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
            if (mEnabled != enabled) {
                Binder.setObserver(enabled ? mBinderCallsStats : null);
                if (enabled) {
                    Binder.setObserver(mBinderCallsStats);
                    Binder.setProxyTransactListener(
                            new Binder.PropagateWorkSourceTransactListener());
                } else {
                    Binder.setObserver(null);
                    Binder.setProxyTransactListener(null);
                }
                mEnabled = enabled;
                mBinderCallsStats.reset();
            }