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

Commit 1d724581 authored by Olivier Gaillard's avatar Olivier Gaillard
Browse files

Tests for binder work source propagation

Test: atest binderLibTest BinderWorkSourceTest
Change-Id: I7265388c96076f8fcd44e02df493d3eec8e96b14
parent ce7357ad
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -400,6 +400,9 @@ public class Binder implements IBinder {
     * }
     * </pre>
     *
     * <p>The work source will be propagated for future outgoing binder transactions
     * executed on this thread.
     *
     * @param workSource The original UID responsible for the binder call.
     * @return token to restore original work source.
     * @hide
@@ -423,6 +426,9 @@ public class Binder implements IBinder {
    /**
     * Clears the work source on this thread.
     *
     * <p>The work source will be propagated for future outgoing binder transactions
     * executed on this thread.
     *
     * @return token to restore original work source.
     * @hide
     **/
@@ -442,6 +448,9 @@ public class Binder implements IBinder {
     *   Binder.restoreCallingWorkSource(token);
     * }
     * </pre>
     *
     * <p>The work source will be propagated for future outgoing binder transactions
     * executed on this thread.
     * @hide
     **/
    @CriticalNative
+6 −0
Original line number Diff line number Diff line
@@ -1316,6 +1316,12 @@
        <service android:name="android.os.BinderThreadPriorityService"
                android:process=":BinderThreadPriorityService" />

        <!-- Used by BinderWorkSourceTest -->
        <service android:name="android.os.BinderWorkSourceService"
                android:process=":BinderWorkSourceService" />
        <service android:name="android.os.BinderWorkSourceNestedService"
                android:process=":BinderWorkSourceNestedService" />

        <!-- Application components used for search manager tests -->

        <activity android:name="android.app.activity.SearchableActivity"
+91 −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.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
* Service used by {@link BinderWorkSourceTest}.
*/
public class BinderWorkSourceNestedService extends Service {
    private final IBinderWorkSourceNestedService.Stub mBinder =
            new IBinderWorkSourceNestedService.Stub() {

        public int[] nestedCallWithWorkSourceToSet(int uidToBlame) {
            final int uid =  Binder.getCallingWorkSourceUid();
            if (uidToBlame != ThreadLocalWorkSource.UID_NONE) {
                Binder.setCallingWorkSourceUid(uidToBlame);
            }
            final int nestedUid = callGetIncomingWorkSourceUid();
            return new int[] {uid, nestedUid};
        }

        public int[] nestedCall() {
            final int uid =  Binder.getCallingWorkSourceUid();
            final int nestedUid = callGetIncomingWorkSourceUid();
            return new int[] {uid, nestedUid};
        }

        private int callGetIncomingWorkSourceUid() {
            BlockingQueue<IBinderWorkSourceService> blockingQueue =
                    new LinkedBlockingQueue<>();
            ServiceConnection mConnection = new ServiceConnection() {
                public void onServiceConnected(ComponentName name, IBinder service) {
                    blockingQueue.add(IBinderWorkSourceService.Stub.asInterface(service));
                }

                public void onServiceDisconnected(ComponentName name) {
                }
            };

            Context context = getApplicationContext();
            context.bindService(
                    new Intent(context, BinderWorkSourceService.class),
                    mConnection, Context.BIND_AUTO_CREATE);

            final IBinderWorkSourceService service;
            try {
                service = blockingQueue.poll(30, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (service == null) {
                throw new RuntimeException("Gave up waiting for BinderWorkSourceService");
            }

            try {
                return service.getIncomingWorkSourceUid();
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            } finally {
                context.unbindService(mConnection);
            }
        }
    };

    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
+36 −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.app.Service;
import android.content.Intent;

/**
 * Service used by {@link BinderWorkSourceTest}.
 */
public class BinderWorkSourceService extends Service {
    private final IBinderWorkSourceService.Stub mBinder =
            new IBinderWorkSourceService.Stub() {
        public int getIncomingWorkSourceUid() {
            return Binder.getCallingWorkSourceUid();
        }
    };

    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
+166 −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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Test whether Binder calls work source is propagated correctly.
 */
@LargeTest
@RunWith(AndroidJUnit4.class)
public class BinderWorkSourceTest {
    private static Context sContext;
    private static final int UID = 100;
    private static final int SECOND_UID = 200;
    private static final int UID_NONE = ThreadLocalWorkSource.UID_NONE;

    private IBinderWorkSourceService mService;
    private IBinderWorkSourceNestedService mNestedService;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = IBinderWorkSourceService.Stub.asInterface(service);
        }

        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }
    };

    private ServiceConnection mNestedConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
            mNestedService = IBinderWorkSourceNestedService.Stub.asInterface(service);
        }

        public void onServiceDisconnected(ComponentName name) {
            mNestedService = null;
        }
    };

    @BeforeClass
    public static void setUpOnce() throws Exception {
        sContext = InstrumentationRegistry.getContext();
    }

    @Before
    public void setUp() throws Exception {
        sContext.bindService(
                new Intent(sContext, BinderWorkSourceService.class),
                mConnection, Context.BIND_AUTO_CREATE);
        sContext.bindService(
                new Intent(sContext, BinderWorkSourceNestedService.class),
                mNestedConnection, Context.BIND_AUTO_CREATE);

        final long timeoutMs = System.currentTimeMillis() + 30_000;
        while ((mService == null || mNestedService == null)
                && System.currentTimeMillis() < timeoutMs) {
            Thread.sleep(1_000);
        }
        assertNotNull("Gave up waiting for BinderWorkSourceService", mService);
        assertNotNull("Gave up waiting for BinderWorkSourceNestedService", mNestedService);
    }

    @After
    public void tearDown() throws Exception {
        sContext.unbindService(mConnection);
        sContext.unbindService(mNestedConnection);
    }

    @Test
    public void setWorkSource() throws Exception {
        Binder.setCallingWorkSourceUid(UID);
        assertEquals(UID, mService.getIncomingWorkSourceUid());
        assertEquals(UID, Binder.getCallingWorkSourceUid());
    }

    @Test
    public void clearWorkSource() throws Exception {
        Binder.setCallingWorkSourceUid(UID);
        Binder.clearCallingWorkSource();
        assertEquals(UID_NONE, mService.getIncomingWorkSourceUid());
        assertEquals(UID_NONE, Binder.getCallingWorkSourceUid());
    }

    @Test
    public void setWorkSource_propagatedForMultipleCalls() throws Exception {
        Binder.setCallingWorkSourceUid(UID);
        assertEquals(UID, mService.getIncomingWorkSourceUid());
        assertEquals(UID, mService.getIncomingWorkSourceUid());
        assertEquals(UID, mService.getIncomingWorkSourceUid());
        assertEquals(UID, Binder.getCallingWorkSourceUid());
    }

    @Test
    public void restoreWorkSource() throws Exception {
        Binder.setCallingWorkSourceUid(UID);
        long token = Binder.clearCallingWorkSource();
        Binder.restoreCallingWorkSource(token);

        assertEquals(UID, mService.getIncomingWorkSourceUid());
        assertEquals(UID, Binder.getCallingWorkSourceUid());
    }

    @Test
    public void nestedSetWorkSoucePropagated() throws Exception {
        Binder.setCallingWorkSourceUid(UID);

        int[] workSources = mNestedService.nestedCallWithWorkSourceToSet(SECOND_UID);
        assertEquals(UID, workSources[0]);
        // UID set in ested call.
        assertEquals(SECOND_UID, workSources[1]);
        // Initial work source restored.
        assertEquals(UID, Binder.getCallingWorkSourceUid());
    }

    @Test
    public void nestedSetWorkSouceDoesNotEnablePropagation() throws Exception {
        int[] workSources = mNestedService.nestedCallWithWorkSourceToSet(UID);
        assertEquals(UID_NONE, workSources[0]);
        // UID set in ested call.
        assertEquals(UID, workSources[1]);
        // Initial work source restored.
        assertEquals(UID_NONE, Binder.getCallingWorkSourceUid());
    }

    @Test
    public void nestedSetWorkSouceNotPropagated() throws Exception {
        Binder.setCallingWorkSourceUid(UID);

        int[] workSources = mNestedService.nestedCall();
        assertEquals(UID, workSources[0]);
        // No UID propagated.
        assertEquals(UID_NONE, workSources[1]);
        // Initial work source restored.
        assertEquals(UID, Binder.getCallingWorkSourceUid());
    }
}
Loading