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

Commit 5ed1dab1 authored by Artem Iglikov's avatar Artem Iglikov
Browse files

Add a test for TransportManager#onPackageAdded().

Also set up robolectric tests for framework services.

Bug: 37616038
Test: make RunFrameworksServicesRoboTests
Change-Id: Ia27a58365a0826ec5bc9f8a7544024b52cfbb3ec
parent 4b950cf6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10475,7 +10475,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
    public ComponentName[] listAllTransportComponents() {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                "listAllTransportComponents");
        return mTransportManager.getAllTransportCompenents();
        return mTransportManager.getAllTransportComponents();
    }
    @Override
+1 −1
Original line number Diff line number Diff line
@@ -2762,7 +2762,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    public ComponentName[] listAllTransportComponents() {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                "listAllTransportComponents");
        return mTransportManager.getAllTransportCompenents();
        return mTransportManager.getAllTransportComponents();
    }

    @Override
+33 −9
Original line number Diff line number Diff line
@@ -41,10 +41,12 @@ import android.util.Log;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.server.EventLogTags;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -57,7 +59,9 @@ public class TransportManager {

    private static final String TAG = "BackupTransportManager";

    private static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
    @VisibleForTesting
    /* package */ static final String SERVICE_ACTION_TRANSPORT_HOST =
            "android.backup.TRANSPORT_HOST";

    private static final long REBINDING_TIMEOUT_UNPROVISIONED_MS = 30 * 1000; // 30 sec
    private static final long REBINDING_TIMEOUT_PROVISIONED_MS = 5 * 60 * 1000; // 5 mins
@@ -95,7 +99,11 @@ public class TransportManager {
            TransportBoundListener listener, Looper looper) {
        mContext = context;
        mPackageManager = context.getPackageManager();
        mTransportWhitelist = (whitelist != null) ? whitelist : new ArraySet<>();
        if (whitelist != null) {
            mTransportWhitelist = whitelist;
        } else {
            mTransportWhitelist = new ArraySet<>();
        }
        mCurrentTransportName = defaultTransport;
        mTransportBoundListener = listener;
        mHandler = new RebindOnTimeoutHandler(looper);
@@ -186,7 +194,7 @@ public class TransportManager {
        }
    }

    ComponentName[] getAllTransportCompenents() {
    ComponentName[] getAllTransportComponents() {
        synchronized (mTransportLock) {
            return mValidTransports.keySet().toArray(new ComponentName[mValidTransports.size()]);
        }
@@ -208,7 +216,8 @@ public class TransportManager {
        }
    }

    void ensureTransportReady(ComponentName transportComponent, SelectBackupTransportCallback listener) {
    void ensureTransportReady(ComponentName transportComponent,
            SelectBackupTransportCallback listener) {
        synchronized (mTransportLock) {
            TransportConnection conn = mValidTransports.get(transportComponent);
            if (conn == null) {
@@ -252,7 +261,7 @@ public class TransportManager {
                intent, 0, UserHandle.USER_SYSTEM);
        if (hosts != null) {
            for (ResolveInfo host : hosts) {
                final ComponentName infoComponentName = host.serviceInfo.getComponentName();
                final ComponentName infoComponentName = getComponentName(host.serviceInfo);
                boolean shouldBind = false;
                if (components != null && packageName != null) {
                    for (String component : components) {
@@ -310,7 +319,7 @@ public class TransportManager {
        Intent intent = new Intent(mTransportServiceIntent)
                .setComponent(componentName);
        return mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
                UserHandle.SYSTEM);
                createSystemUserHandle());
    }

    private class TransportConnection implements ServiceConnection {
@@ -437,7 +446,8 @@ public class TransportManager {
        }

        private long getRebindTimeout() {
            final boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
            final boolean isDeviceProvisioned = Settings.Global.getInt(
                    mContext.getContentResolver(),
                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
            return isDeviceProvisioned
                    ? REBINDING_TIMEOUT_PROVISIONED_MS
@@ -492,4 +502,18 @@ public class TransportManager {
            Slog.v(TAG, message);
        }
    }

    // These only exists to make it testable with Robolectric, which is not updated to API level 24
    // yet.
    // TODO: Get rid of this once Robolectric is updated.
    private static ComponentName getComponentName(ServiceInfo serviceInfo) {
        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
    }

    // These only exists to make it testable with Robolectric, which is not updated to API level 24
    // yet.
    // TODO: Get rid of this once Robolectric is updated.
    private static UserHandle createSystemUserHandle() {
        return new UserHandle(UserHandle.USER_SYSTEM);
    }
}
+76 −0
Original line number Diff line number Diff line
# Copyright (C) 2016 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.


############################################################
# FrameworksServicesLib app just for Robolectric test target.  #
############################################################
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_PACKAGE_NAME := FrameworksServicesLib
LOCAL_MODULE_TAGS := optional

LOCAL_PRIVILEGED_MODULE := true

LOCAL_STATIC_JAVA_LIBRARIES := \
    frameworks-base-testutils \
    services.backup \
    services.core \
    android-support-test \
    mockito-target-minus-junit4 \
    platform-test-annotations \
    truth-prebuilt

include $(BUILD_PACKAGE)

#############################################
# FrameworksServices Robolectric test target. #
#############################################
include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)

# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
    platform-system-robolectric \
    truth-prebuilt

LOCAL_JAVA_LIBRARIES := \
    junit \
    platform-robolectric-prebuilt

LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
LOCAL_MODULE := FrameworksServicesRoboTests

LOCAL_MODULE_TAGS := optional

include $(BUILD_STATIC_JAVA_LIBRARY)

#############################################################
# FrameworksServices runner target to run the previous target. #
#############################################################
include $(CLEAR_VARS)

LOCAL_MODULE := RunFrameworksServicesRoboTests

LOCAL_SDK_VERSION := current

LOCAL_STATIC_JAVA_LIBRARIES := \
    FrameworksServicesRoboTests

LOCAL_TEST_PACKAGE := FrameworksServicesLib

include prebuilts/misc/common/robolectric/run_robotests.mk
+137 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 com.android.server.backup;

import static com.google.common.truth.Truth.assertThat;

import android.annotation.RequiresPermission;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.UserHandle;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.res.ResourceLoader;
import org.robolectric.res.builder.DefaultPackageManager;
import org.robolectric.res.builder.RobolectricPackageManager;
import org.robolectric.shadows.ShadowContextImpl;
import org.robolectric.shadows.ShadowLooper;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(
        manifest = Config.NONE,
        sdk = 23,
        shadows = {TransportManagerTest.ShadowContextImplWithBindServiceAsUser.class}
)
public class TransportManagerTest {
    private static final String PACKAGE_NAME = "some.package.name";
    private static final String TRANSPORT1_NAME = "transport1.name";
    private static final String TRANSPORT2_NAME = "transport2.name";
    private static final ComponentName TRANSPORT1_COMPONENT_NAME = new ComponentName(PACKAGE_NAME,
            TRANSPORT1_NAME);
    private static final ComponentName TRANSPORT2_COMPONENT_NAME = new ComponentName(PACKAGE_NAME,
            TRANSPORT2_NAME);
    private static final List<ComponentName> TRANSPORTS_COMPONENT_NAMES = Arrays.asList(
            TRANSPORT1_COMPONENT_NAME, TRANSPORT2_COMPONENT_NAME);

    private RobolectricPackageManager mPackageManager;

    @Mock private TransportManager.TransportBoundListener mTransportBoundListener;

    @Before
    public void setUp() {
        mPackageManager = new DefaultPackageManagerWithQueryIntentServicesAsUser(
                RuntimeEnvironment.getAppResourceLoader());
        RuntimeEnvironment.setRobolectricPackageManager(mPackageManager);
    }

    @Test
    public void onPackageAdded_bindsToAllTransports() {
        Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
        intent.setPackage(PACKAGE_NAME);

        PackageInfo packageInfo = new PackageInfo();
        packageInfo.packageName = PACKAGE_NAME;
        packageInfo.applicationInfo = new ApplicationInfo();
        packageInfo.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;

        mPackageManager.addPackage(packageInfo);

        ResolveInfo transport1 = new ResolveInfo();
        transport1.serviceInfo = new ServiceInfo();
        transport1.serviceInfo.packageName = PACKAGE_NAME;
        transport1.serviceInfo.name = TRANSPORT1_NAME;

        ResolveInfo transport2 = new ResolveInfo();
        transport2.serviceInfo = new ServiceInfo();
        transport2.serviceInfo.packageName = PACKAGE_NAME;
        transport2.serviceInfo.name = TRANSPORT2_NAME;

        mPackageManager.addResolveInfoForIntent(intent, Arrays.asList(transport1, transport2));

        TransportManager transportManager = new TransportManager(
                RuntimeEnvironment.application.getApplicationContext(),
                new HashSet<>(TRANSPORTS_COMPONENT_NAMES),
                null,
                mTransportBoundListener,
                ShadowLooper.getMainLooper());
        transportManager.onPackageAdded(PACKAGE_NAME);

        assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
                TRANSPORTS_COMPONENT_NAMES);
    }

    private static class DefaultPackageManagerWithQueryIntentServicesAsUser extends
            DefaultPackageManager {

        /* package */ DefaultPackageManagerWithQueryIntentServicesAsUser(
                ResourceLoader appResourceLoader) {
            super(appResourceLoader);
        }

        @Override
        public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
            return super.queryIntentServices(intent, flags);
        }
    }

    @Implements(className = ShadowContextImpl.CLASS_NAME)
    public static class ShadowContextImplWithBindServiceAsUser extends ShadowContextImpl {

        @Implementation
        public boolean bindServiceAsUser(@RequiresPermission Intent service, ServiceConnection conn,
                int flags, UserHandle user) {
            return true;
        }
    }
}