/*
 * 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.notification;

import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT;
import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.IBinder;
import android.os.IInterface;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.SparseArray;
import android.util.Xml;

import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.server.UiServiceTestCase;

import com.google.android.collect.Lists;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

public class ManagedServicesTest extends UiServiceTestCase {

    @Mock
    private IPackageManager mIpm;
    @Mock
    private PackageManager mPm;
    @Mock
    private UserManager mUm;
    @Mock
    private ManagedServices.UserProfiles mUserProfiles;
    Object mLock = new Object();

    UserInfo mZero = new UserInfo(0, "zero", 0);
    UserInfo mTen = new UserInfo(10, "ten", 0);

    private static final String SETTING = "setting";
    private static final String SECONDARY_SETTING = "secondary_setting";

    private ArrayMap<Integer, String> mExpectedPrimaryPackages;
    private ArrayMap<Integer, String> mExpectedPrimaryComponentNames;
    private ArrayMap<Integer, String> mExpectedSecondaryPackages;
    private ArrayMap<Integer, String> mExpectedSecondaryComponentNames;

    // type : user : list of approved
    private ArrayMap<Integer, ArrayMap<Integer, String>> mExpectedPrimary = new ArrayMap<>();
    private ArrayMap<Integer, ArrayMap<Integer, String>> mExpectedSecondary = new ArrayMap<>();

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        getContext().setMockPackageManager(mPm);
        getContext().addMockSystemService(Context.USER_SERVICE, mUm);

        List<UserInfo> users = new ArrayList<>();
        users.add(mZero);
        users.add(mTen);
        users.add(new UserInfo(11, "11", 0));
        users.add(new UserInfo(12, "12", 0));
        for (UserInfo user : users) {
            when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
        }
        when(mUm.getUsers()).thenReturn(users);
        IntArray profileIds = new IntArray();
        profileIds.add(0);
        profileIds.add(11);
        profileIds.add(10);
        profileIds.add(12);
        when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);

        mExpectedPrimaryPackages = new ArrayMap<>();
        mExpectedPrimaryPackages.put(0, "this.is.a.package.name:another.package");
        mExpectedPrimaryPackages.put(10, "this.is.another.package");
        mExpectedPrimaryPackages.put(11, "");
        mExpectedPrimaryPackages.put(12, "bananas!");
        mExpectedPrimaryComponentNames = new ArrayMap<>();
        mExpectedPrimaryComponentNames.put(0, "this.is.a.package.name/Ba:another.package/B1");
        mExpectedPrimaryComponentNames.put(10, "this.is.another.package/M1");
        mExpectedPrimaryComponentNames.put(11, "");
        mExpectedPrimaryComponentNames.put(12, "bananas!/Bananas!");
        mExpectedPrimary.put(APPROVAL_BY_PACKAGE, mExpectedPrimaryPackages);
        mExpectedPrimary.put(APPROVAL_BY_COMPONENT, mExpectedPrimaryComponentNames);

        mExpectedSecondaryComponentNames = new ArrayMap<>();
        mExpectedSecondaryComponentNames.put(0, "secondary/component.Name");
        mExpectedSecondaryComponentNames.put(10,
                "this.is.another.package/with.Component:component/2:package/component2");
        mExpectedSecondaryPackages = new ArrayMap<>();
        mExpectedSecondaryPackages.put(0, "secondary");
        mExpectedSecondaryPackages.put(10,
                "this.is.another.package:component:package");
        mExpectedSecondary.put(APPROVAL_BY_PACKAGE, mExpectedSecondaryPackages);
        mExpectedSecondary.put(APPROVAL_BY_COMPONENT, mExpectedSecondaryComponentNames);
    }

    @Test
    public void testBackupAndRestore_migration() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);

            for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
                service.onSettingRestored(
                        service.getConfig().secureSettingName,
                        mExpectedPrimary.get(approvalLevel).get(userId),
                        Build.VERSION_CODES.O, userId);
            }
            verifyExpectedApprovedEntries(service, true);

            for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
                service.onSettingRestored(service.getConfig().secondarySettingName,
                        mExpectedSecondary.get(approvalLevel).get(userId), Build.VERSION_CODES.O,
                        userId);
            }
            verifyExpectedApprovedEntries(service);
        }
    }

    @Test
    public void testBackupAndRestore_migration_preO() throws Exception {
        ArrayMap<Integer, String> backupPrimaryPackages = new ArrayMap<>();
        backupPrimaryPackages.put(0, "backup.0:backup:0a");
        backupPrimaryPackages.put(10, "10.backup");
        backupPrimaryPackages.put(11, "eleven");
        backupPrimaryPackages.put(12, "");
        ArrayMap<Integer, String> backupPrimaryComponentNames = new ArrayMap<>();
        backupPrimaryComponentNames.put(0, "backup.first/whatever:a/b");
        backupPrimaryComponentNames.put(10, "again/M1");
        backupPrimaryComponentNames.put(11, "orange/youglad:itisnot/banana");
        backupPrimaryComponentNames.put(12, "");
        ArrayMap<Integer, ArrayMap<Integer, String>> backupPrimary = new ArrayMap<>();
        backupPrimary.put(APPROVAL_BY_PACKAGE, backupPrimaryPackages);
        backupPrimary.put(APPROVAL_BY_COMPONENT, backupPrimaryComponentNames);

        ArrayMap<Integer, String> backupSecondaryComponentNames = new ArrayMap<>();
        backupSecondaryComponentNames.put(0, "secondary.1/component.Name");
        backupSecondaryComponentNames.put(10,
                "this.is.another.package.backup/with.Component:component.backup/2");
        ArrayMap<Integer, String> backupSecondaryPackages = new ArrayMap<>();
        backupSecondaryPackages.put(0, "");
        backupSecondaryPackages.put(10,
                "this.is.another.package.backup:package.backup");
        ArrayMap<Integer, ArrayMap<Integer, String>> backupSecondary = new ArrayMap<>();
        backupSecondary.put(APPROVAL_BY_PACKAGE, backupSecondaryPackages);
        backupSecondary.put(APPROVAL_BY_COMPONENT, backupSecondaryComponentNames);

        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);

            // not an expected flow but a way to get data into the settings
            for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
                service.onSettingRestored(
                        service.getConfig().secureSettingName,
                        mExpectedPrimary.get(approvalLevel).get(userId),
                        Build.VERSION_CODES.O, userId);
            }

            for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
                service.onSettingRestored(service.getConfig().secondarySettingName,
                        mExpectedSecondary.get(approvalLevel).get(userId), Build.VERSION_CODES.O,
                        userId);
            }

            // actual test
            for (int userId : backupPrimary.get(approvalLevel).keySet()) {
                service.onSettingRestored(
                        service.getConfig().secureSettingName,
                        backupPrimary.get(approvalLevel).get(userId),
                        Build.VERSION_CODES.N_MR1, userId);
            }
            verifyExpectedApprovedEntries(service, true);

            for (int userId : backupSecondary.get(approvalLevel).keySet()) {
                service.onSettingRestored(service.getConfig().secondarySettingName,
                        backupSecondary.get(approvalLevel).get(userId),
                        Build.VERSION_CODES.N_MR1, userId);
            }
            verifyExpectedApprovedEntries(service);
            verifyExpectedApprovedEntries(service, backupPrimary.get(approvalLevel));
            verifyExpectedApprovedEntries(service, backupSecondary.get(approvalLevel));
        }
    }

    @Test
    public void testReadXml_migrationFromSettings() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);

            // approved services aren't in xml
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})),
                    null);
            writeExpectedValuesToSettings(approvalLevel);

            service.migrateToXml();

            verifyExpectedApprovedEntries(service);
        }
    }

    @Test
    public void testReadXml() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);

            loadXml(service);

            verifyExpectedApprovedEntries(service);

            int[] invalidUsers = new int[] {98, 99};
            for (int invalidUser : invalidUsers) {
                assertFalse("service type " + service.mApprovalLevel + ":"
                                + invalidUser + " is allowed for user " + invalidUser,
                        service.isPackageOrComponentAllowed(
                                String.valueOf(invalidUser), invalidUser));
            }
        }
    }

    @Test
    public void testReadXml_appendsListOfApprovedComponents() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);

            String preApprovedPackage = "some.random.package";
            String preApprovedComponent = "some.random.package/C1";

            List<String> packages = new ArrayList<>();
            packages.add(preApprovedPackage);
            addExpectedServices(service, packages, 0);

            service.setPackageOrComponentEnabled(preApprovedComponent, 0, true, true);

            loadXml(service);

            verifyExpectedApprovedEntries(service);

            String verifyValue  = (approvalLevel == APPROVAL_BY_COMPONENT)
                    ? preApprovedComponent
                    : preApprovedPackage;
            assertTrue(service.isPackageOrComponentAllowed(verifyValue, 0));
        }
    }

    /** Test that restore ignores the user id attribute and applies the data to the target user. */
    @Test
    public void testReadXml_onlyRestoresForTargetUser() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service =
                    new TestManagedServices(
                            getContext(), mLock, mUserProfiles, mIpm, approvalLevel);
            String testPackage = "user.test.package";
            String testComponent = "user.test.component/C1";
            String resolvedValue =
                    (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent : testPackage;
            XmlPullParser parser =
                    getParserWithEntries(service, getXmlEntry(resolvedValue, 0, true));

            service.readXml(parser, null, true, 10);

            assertFalse(service.isPackageOrComponentAllowed(resolvedValue, 0));
            assertTrue(service.isPackageOrComponentAllowed(resolvedValue, 10));
        }
    }

    /** Test that restore ignores the user id attribute and applies the data to the target user. */
    @Test
    public void testWriteReadXml_writeReadDefaults() throws Exception {
        // setup
        ManagedServices service1 =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        ManagedServices service2 =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        XmlSerializer serializer = new FastXmlSerializer();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream outStream = new BufferedOutputStream(baos);
        serializer.setOutput(outStream, "utf-8");

        //data setup
        service1.addDefaultComponentOrPackage("package/class");
        serializer.startDocument(null, true);
        service1.writeXml(serializer, false, 0);
        serializer.endDocument();
        outStream.flush();

        final XmlPullParser parser = Xml.newPullParser();
        BufferedInputStream input = new BufferedInputStream(
                new ByteArrayInputStream(baos.toByteArray()));

        parser.setInput(input, StandardCharsets.UTF_8.name());
        XmlUtils.beginDocument(parser, "test");
        service2.readXml(parser, null, false, 0);
        ArraySet<ComponentName> defaults = service2.getDefaultComponents();

        assertEquals(1, defaults.size());
        assertEquals(new ComponentName("package", "class"), defaults.valueAt(0));

    }

    @Test
    public void resetPackage_enableDefaultsOnly() {
        // setup
        ManagedServices service =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        service.addApprovedList(
                "package/not-default:another-package/not-default:package2/default",
                0, true);
        service.addDefaultComponentOrPackage("package/default");
        service.addDefaultComponentOrPackage("package2/default");

        ArrayMap<Boolean, ArrayList<ComponentName>> componentsToActivate =
                service.resetComponents("package", 0);

        assertEquals(1, componentsToActivate.get(true).size());
        assertEquals(new ComponentName("package", "default"),
                componentsToActivate.get(true).get(0));
    }


    @Test
    public void resetPackage_nonDefaultsRemoved() {
        // setup
        ManagedServices service =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        service.addApprovedList(
                "package/not-default:another-package/not-default:package2/default",
                0, true);
        service.addDefaultComponentOrPackage("package/default");
        service.addDefaultComponentOrPackage("package2/default");

        ArrayMap<Boolean, ArrayList<ComponentName>> componentsToActivate =
                service.resetComponents("package", 0);

        assertEquals(1, componentsToActivate.get(true).size());
        assertEquals(new ComponentName("package", "not-default"),
                componentsToActivate.get(false).get(0));
    }

    @Test
    public void resetPackage_onlyDefaultsOnly() {
        // setup
        ManagedServices service =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        service.addApprovedList(
                "package/not-default:another-package/not-default:package2/default",
                0, true);
        service.addDefaultComponentOrPackage("package/default");
        service.addDefaultComponentOrPackage("package2/default");

        assertEquals(3, service.getAllowedComponents(0).size());

        service.resetComponents("package", 0);

        List<ComponentName> components =  service.getAllowedComponents(0);
        assertEquals(3, components.size());
        assertTrue(components.contains(new ComponentName("package", "default")));
    }

    @Test
    public void resetPackage_affectCurrentUserOnly() {
        // setup
        ManagedServices service =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        service.addApprovedList(
                "package/not-default:another-package/not-default:package2/default",
                0, true);
        service.addApprovedList(
                "package/not-default:another-package/not-default:package2/default",
                1, true);
        service.addDefaultComponentOrPackage("package/default");
        service.addDefaultComponentOrPackage("package2/default");

        service.resetComponents("package", 0);

        List<ComponentName> components =  service.getAllowedComponents(1);
        assertEquals(3, components.size());
    }

    @Test
    public void resetPackage_samePackageMultipleClasses() {
        // setup
        ManagedServices service =
                new TestManagedServices(
                        getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
        service.addApprovedList(
                "package/not-default:another-package/not-default:package2/default",
                0, true);
        service.addApprovedList(
                "package/class:another-package/class:package2/class",
                0, true);
        service.addDefaultComponentOrPackage("package/default");
        service.addDefaultComponentOrPackage("package2/default");

        service.resetComponents("package", 0);

        List<ComponentName> components =  service.getAllowedComponents(0);
        assertEquals(5, components.size());
        assertTrue(components.contains(new ComponentName("package", "default")));
    }

    /** Test that backup only writes packages/components that belong to the target user. */
    @Test
    public void testWriteXml_onlyBackupsForTargetUser() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service =
                    new TestManagedServices(
                            getContext(), mLock, mUserProfiles, mIpm, approvalLevel);
            // Set up components.
            String testPackage0 = "user0.test.package";
            String testComponent0 = "user0.test.component/C1";
            String testPackage10 = "user10.test.package";
            String testComponent10 = "user10.test.component/C1";
            String resolvedValue0 =
                    (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent0 : testPackage0;
            String resolvedValue10 =
                    (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent10 : testPackage10;
            addExpectedServices(
                    service, Collections.singletonList(service.getPackageName(resolvedValue0)), 0);
            addExpectedServices(
                    service,
                    Collections.singletonList(service.getPackageName(resolvedValue10)),
                    10);
            XmlPullParser parser =
                    getParserWithEntries(
                            service,
                            getXmlEntry(resolvedValue0, 0, true),
                            getXmlEntry(resolvedValue10, 10, true));
            service.readXml(parser, null, false, UserHandle.USER_ALL);

            // Write backup.
            XmlSerializer serializer = new FastXmlSerializer();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
            serializer.startDocument(null, true);
            service.writeXml(serializer, true, 10);
            serializer.endDocument();
            serializer.flush();

            // Reset values.
            service.setPackageOrComponentEnabled(resolvedValue0, 0, true, false);
            service.setPackageOrComponentEnabled(resolvedValue10, 10, true, false);

            // Parse backup via restore.
            XmlPullParser restoreParser = Xml.newPullParser();
            restoreParser.setInput(
                    new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
            restoreParser.nextTag();
            service.readXml(restoreParser, null, true, 10);

            assertFalse(service.isPackageOrComponentAllowed(resolvedValue0, 0));
            assertFalse(service.isPackageOrComponentAllowed(resolvedValue0, 10));
            assertTrue(service.isPackageOrComponentAllowed(resolvedValue10, 10));
        }
    }

    @Test
    public void testWriteXml_trimsMissingServices() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            loadXml(service);

            // remove missing
            mExpectedPrimaryPackages.put(0, "another.package");
            mExpectedPrimaryPackages.remove(12);
            mExpectedPrimaryComponentNames.put(0, "another.package/B1");
            mExpectedPrimaryComponentNames.remove(12);
            mExpectedSecondaryPackages.put(10, "this.is.another.package:component");
            mExpectedSecondaryComponentNames.put(
                    10, "this.is.another.package/with.Component:component/2");

            for (UserInfo userInfo : mUm.getUsers()) {
                List<String> entriesExpectedToHaveServices = new ArrayList<>();
                if (mExpectedPrimary.get(approvalLevel).containsKey(userInfo.id)) {
                    for (String packageOrComponent :
                            mExpectedPrimary.get(approvalLevel).get(userInfo.id).split(":")) {
                        if (!TextUtils.isEmpty(packageOrComponent)) {
                            entriesExpectedToHaveServices.add(
                                    service.getPackageName(packageOrComponent));
                        }
                    }
                }
                if (mExpectedSecondary.get(approvalLevel).containsKey(userInfo.id)) {
                    for (String packageOrComponent :
                            mExpectedSecondary.get(approvalLevel).get(userInfo.id).split(":")) {
                        if (!TextUtils.isEmpty(packageOrComponent)) {
                            entriesExpectedToHaveServices.add(
                                    service.getPackageName(packageOrComponent));
                        }
                    }
                }
                addExpectedServices(service, entriesExpectedToHaveServices, userInfo.id);
            }

            XmlSerializer serializer = new FastXmlSerializer();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
            serializer.startDocument(null, true);
            for (UserInfo userInfo : mUm.getUsers()) {
                service.writeXml(serializer, true, userInfo.id);
            }
            serializer.endDocument();
            serializer.flush();

            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(new BufferedInputStream(
                    new ByteArrayInputStream(baos.toByteArray())), null);
            parser.nextTag();
            for (UserInfo userInfo : mUm.getUsers()) {
                service.readXml(parser, null, true, userInfo.id);
            }

            verifyExpectedApprovedEntries(service);
            assertFalse(service.isPackageOrComponentAllowed("this.is.a.package.name", 0));
            assertFalse(service.isPackageOrComponentAllowed("bananas!", 12));
            assertFalse(service.isPackageOrComponentAllowed("package/component2", 10));
        }
    }

    @Test
    public void testWriteXml_writesSetting() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            loadXml(service);

            XmlSerializer serializer = new FastXmlSerializer();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
            serializer.startDocument(null, true);
            service.writeXml(serializer, false, UserHandle.USER_ALL);
            serializer.endDocument();
            serializer.flush();

            for (int userId : mUserProfiles.getCurrentProfileIds().toArray()) {
                List<String> expected =
                        stringToList(mExpectedPrimary.get(approvalLevel).get(userId));
                List<String> actual = stringToList(Settings.Secure.getStringForUser(
                        getContext().getContentResolver(),
                        service.getConfig().secureSettingName, userId));
                assertContentsInAnyOrder(actual, expected);
            }
        }
    }

    @Test
    public void rebindServices_onlyBindsExactMatchesIfComponent() throws Exception {
        // If the primary and secondary lists contain component names, only those components within
        // the package should be matched
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                mIpm,
                ManagedServices.APPROVAL_BY_COMPONENT);

        List<String> packages = new ArrayList<>();
        packages.add("package");
        packages.add("anotherPackage");
        addExpectedServices(service, packages, 0);

        // only 2 components are approved per package
        mExpectedPrimaryComponentNames.clear();
        mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
        mExpectedSecondaryComponentNames.clear();
        mExpectedSecondaryComponentNames.put(0, "anotherPackage/C1:anotherPackage/C2");

        loadXml(service);

        // verify the 2 components per package are enabled (bound)
        verifyExpectedBoundEntries(service, true);
        verifyExpectedBoundEntries(service, false);

        // verify the last component per package is not enabled/we don't try to bind to it
        for (String pkg : packages) {
            ComponentName unapprovedAdditionalComponent =
                    ComponentName.unflattenFromString(pkg + "/C3");
            assertFalse(
                    service.isComponentEnabledForCurrentProfiles(
                            unapprovedAdditionalComponent));
            verify(mIpm, never()).getServiceInfo(
                    eq(unapprovedAdditionalComponent), anyInt(), anyInt());
        }
    }

    @Test
    public void rebindServices_bindsEverythingInAPackage() throws Exception {
        // If the primary and secondary lists contain packages, all components within those packages
        // should be bound
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_PACKAGE);

        List<String> packages = new ArrayList<>();
        packages.add("package");
        packages.add("packagea");
        addExpectedServices(service, packages, 0);

        // 2 approved packages
        mExpectedPrimaryPackages.clear();
        mExpectedPrimaryPackages.put(0, "package");
        mExpectedSecondaryPackages.clear();
        mExpectedSecondaryPackages.put(0, "packagea");

        loadXml(service);

        // verify the 3 components per package are enabled (bound)
        verifyExpectedBoundEntries(service, true);
        verifyExpectedBoundEntries(service, false);
    }

    @Test
    public void testPackageUninstall_packageNoLongerInApprovedList() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            writeExpectedValuesToSettings(approvalLevel);
            service.migrateToXml();

            mExpectedPrimaryPackages.put(0, "another.package");
            mExpectedPrimaryComponentNames.put(0, "another.package/B1");
            service.onPackagesChanged(true, new String[]{"this.is.a.package.name"}, new int[]{103});

            verifyExpectedApprovedEntries(service);
        }
    }

    @Test
    public void testPackageUninstall_componentNoLongerInApprovedList() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            writeExpectedValuesToSettings(approvalLevel);
            service.migrateToXml();

            mExpectedSecondaryComponentNames.put(10, "component/2");
            mExpectedSecondaryPackages.put(10, "component");
            service.onPackagesChanged(true, new String[]{"this.is.another.package"}, new int[]{
                    UserHandle.PER_USER_RANGE + 1});

            verifyExpectedApprovedEntries(service);
        }
    }

    @Test
    public void testIsPackageAllowed() {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            writeExpectedValuesToSettings(approvalLevel);
            service.migrateToXml();

            verifyExpectedApprovedPackages(service);
        }
    }

    @Test
    public void testUpgradeAppBindsNewServices() throws Exception {
        // If the primary and secondary lists contain component names, only those components within
        // the package should be matched
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                mIpm,
                ManagedServices.APPROVAL_BY_PACKAGE);

        List<String> packages = new ArrayList<>();
        packages.add("package");
        addExpectedServices(service, packages, 0);

        // only 2 components are approved per package
        mExpectedPrimaryComponentNames.clear();
        mExpectedPrimaryPackages.clear();
        mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
        mExpectedSecondaryComponentNames.clear();
        mExpectedSecondaryPackages.clear();

        loadXml(service);

        // new component expected
        mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2:package/C3");

        service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});

        // verify the 3 components per package are enabled (bound)
        verifyExpectedBoundEntries(service, true);

        // verify the last component per package is not enabled/we don't try to bind to it
        for (String pkg : packages) {
            ComponentName unapprovedAdditionalComponent =
                    ComponentName.unflattenFromString(pkg + "/C3");
            assertFalse(
                    service.isComponentEnabledForCurrentProfiles(
                            unapprovedAdditionalComponent));
            verify(mIpm, never()).getServiceInfo(
                    eq(unapprovedAdditionalComponent), anyInt(), anyInt());
        }
    }

    @Test
    public void testSetPackageOrComponentEnabled() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            ArrayMap<Integer, ArrayList<String>> expectedEnabled = new ArrayMap<>();
            expectedEnabled.put(0,
                    Lists.newArrayList(new String[]{"package/Comp", "package/C2", "again/M4"}));
            expectedEnabled.put(10,
                    Lists.newArrayList(new String[]{"user10package/B", "user10/Component",
                            "user10package1/K", "user10.3/Component", "user10package2/L",
                            "user10.4/Component"}));

            for (int userId : expectedEnabled.keySet()) {
                ArrayList<String> expectedForUser = expectedEnabled.get(userId);
                for (int i = 0; i < expectedForUser.size(); i++) {
                    boolean primary = i % 2 == 0;
                    service.setPackageOrComponentEnabled(expectedForUser.get(i), userId, primary,
                            true);
                }
            }

            // verify everything added is approved
            for (int userId : expectedEnabled.keySet()) {
                ArrayList<String> expectedForUser = expectedEnabled.get(userId);
                for (int i = 0; i < expectedForUser.size(); i++) {
                    String verifyValue  = (approvalLevel == APPROVAL_BY_COMPONENT)
                            ? expectedForUser.get(i)
                            : service.getPackageName(expectedForUser.get(i));
                    assertTrue("Not allowed: user: " + userId + " entry: " + verifyValue
                            + " for approval level " + approvalLevel,
                            service.isPackageOrComponentAllowed(verifyValue, userId));
                }
            }

            ArrayMap<Integer, ArrayList<String>> expectedNoAccess = new ArrayMap<>();
            for (int userId : expectedEnabled.keySet()) {
                ArrayList<String> expectedForUser = expectedEnabled.get(userId);
                for (int i = expectedForUser.size() - 1; i >= 0; i--) {
                    ArrayList<String> removed = new ArrayList<>();
                    if (i % 3 == 0) {
                        String revokeAccessFor = expectedForUser.remove(i);
                        removed.add(revokeAccessFor);
                        service.setPackageOrComponentEnabled(
                                revokeAccessFor, userId, i % 2 == 0, false);
                    }
                    expectedNoAccess.put(userId, removed);
                }
            }

            // verify everything still there is approved
            for (int userId : expectedEnabled.keySet()) {
                ArrayList<String> expectedForUser = expectedEnabled.get(userId);
                for (int i = 0; i < expectedForUser.size(); i++) {
                    String verifyValue  = (approvalLevel == APPROVAL_BY_COMPONENT)
                            ? expectedForUser.get(i)
                            : service.getPackageName(expectedForUser.get(i));
                    assertTrue("Not allowed: user: " + userId + " entry: " + verifyValue,
                            service.isPackageOrComponentAllowed(verifyValue, userId));
                }
            }
            // verify everything removed isn't
            for (int userId : expectedNoAccess.keySet()) {
                ArrayList<String> notExpectedForUser = expectedNoAccess.get(userId);
                for (int i = 0; i < notExpectedForUser.size(); i++) {
                    assertFalse(
                            "Is allowed: user: " + userId + " entry: " + notExpectedForUser.get(i),
                            service.isPackageOrComponentAllowed(notExpectedForUser.get(i), userId));
                }
            }
        }
    }

    @Test
    public void testGetAllowedPackages_byUser() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            loadXml(service);

            List<String> allowedPackagesForUser0 = new ArrayList<>();
            allowedPackagesForUser0.add("this.is.a.package.name");
            allowedPackagesForUser0.add("another.package");
            allowedPackagesForUser0.add("secondary");

            List<String> actual = service.getAllowedPackages(0);
            assertEquals(3, actual.size());
            for (String pkg : allowedPackagesForUser0) {
                assertTrue(actual.contains(pkg));
            }

            List<String> allowedPackagesForUser10 = new ArrayList<>();
            allowedPackagesForUser10.add("this.is.another.package");
            allowedPackagesForUser10.add("package");
            allowedPackagesForUser10.add("this.is.another.package");
            allowedPackagesForUser10.add("component");

            actual = service.getAllowedPackages(10);
            assertEquals(4, actual.size());
            for (String pkg : allowedPackagesForUser10) {
                assertTrue(actual.contains(pkg));
            }
        }
    }

    @Test
    public void testGetAllowedComponentsByUser() throws Exception {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);
        loadXml(service);

        List<ComponentName> expected = new ArrayList<>();
        expected.add(ComponentName.unflattenFromString("this.is.another.package/M1"));
        expected.add(ComponentName.unflattenFromString("this.is.another.package/with.Component"));
        expected.add(ComponentName.unflattenFromString("component/2"));
        expected.add(ComponentName.unflattenFromString("package/component2"));

        List<ComponentName> actual = service.getAllowedComponents(10);

        assertContentsInAnyOrder(expected, actual);

        assertEquals(expected.size(), actual.size());

        for (ComponentName cn : expected) {
            assertTrue("Actual missing " + cn, actual.contains(cn));
        }

        for (ComponentName cn : actual) {
            assertTrue("Actual contains extra " + cn, expected.contains(cn));
        }
    }

    @Test
    public void testGetAllowedComponents_approvalByPackage() throws Exception {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_PACKAGE);
        loadXml(service);

        assertEquals(0, service.getAllowedComponents(10).size());
    }

    @Test
    public void testGetAllowedPackages() throws Exception {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                mIpm, APPROVAL_BY_COMPONENT);
        loadXml(service);
        service.mApprovalLevel = APPROVAL_BY_PACKAGE;
        loadXml(service);

        List<String> allowedPackages = new ArrayList<>();
        allowedPackages.add("this.is.a.package.name");
        allowedPackages.add("another.package");
        allowedPackages.add("secondary");
        allowedPackages.add("this.is.another.package");
        allowedPackages.add("package");
        allowedPackages.add("component");
        allowedPackages.add("bananas!");

        Set<String> actual = service.getAllowedPackages();
        assertEquals(allowedPackages.size(), actual.size());
        for (String pkg : allowedPackages) {
            assertTrue(actual.contains(pkg));
        }
    }

    @Test
    public void testOnUserRemoved() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            loadXml(service);

            ArrayMap<Integer, String> verifyMap = mExpectedPrimary.get(service.mApprovalLevel);
            String user0 = verifyMap.remove(0);
            verifyMap = mExpectedSecondary.get(service.mApprovalLevel);
            user0 = user0 + ":" + verifyMap.remove(0);

            service.onUserRemoved(0);

            for (String verifyValue : user0.split(":")) {
                if (!TextUtils.isEmpty(verifyValue)) {
                    assertFalse("service type " + service.mApprovalLevel + ":" + verifyValue
                            + " is still allowed",
                            service.isPackageOrComponentAllowed(verifyValue, 0));
                }
            }

            verifyExpectedApprovedEntries(service);
        }
    }

    @Test
    public void testIsSameUser() {
        IInterface service = mock(IInterface.class);
        when(service.asBinder()).thenReturn(mock(IBinder.class));
        ManagedServices services = new TestManagedServices(getContext(), mLock, mUserProfiles,
                mIpm, APPROVAL_BY_PACKAGE);
        services.registerService(service, null, 10);
        ManagedServices.ManagedServiceInfo info = services.checkServiceTokenLocked(service);
        info.isSystem = true;

        assertFalse(services.isSameUser(service, 0));
        assertTrue(services.isSameUser(service, 10));
    }

    @Test
    public void testGetAllowedComponents() throws Exception {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);
        loadXml(service);

        SparseArray<ArraySet<ComponentName>> expected = new SparseArray<>();

        ArraySet<ComponentName> expected10 = new ArraySet<>();
        expected10.add(ComponentName.unflattenFromString("this.is.another.package/M1"));
        expected10.add(ComponentName.unflattenFromString("this.is.another.package/with.Component"));
        expected10.add(ComponentName.unflattenFromString("component/2"));
        expected10.add(ComponentName.unflattenFromString("package/component2"));
        expected.put(10, expected10);
        ArraySet<ComponentName> expected0 = new ArraySet<>();
        expected0.add(ComponentName.unflattenFromString("secondary/component.Name"));
        expected0.add(ComponentName.unflattenFromString("this.is.a.package.name/Ba"));
        expected0.add(ComponentName.unflattenFromString("another.package/B1"));
        expected.put(0, expected0);
        ArraySet<ComponentName> expected12 = new ArraySet<>();
        expected12.add(ComponentName.unflattenFromString("bananas!/Bananas!"));
        expected.put(12, expected12);
        expected.put(11, new ArraySet<>());

        SparseArray<ArraySet<ComponentName>> actual =
                service.getAllowedComponents(mUserProfiles.getCurrentProfileIds());

        assertContentsInAnyOrder(expected, actual);
    }

    @Test
    public void testPopulateComponentsToUnbind_forceRebind() {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);

        IInterface iInterface = mock(IInterface.class);
        when(iInterface.asBinder()).thenReturn(mock(IBinder.class));

        ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo(
                iInterface, ComponentName.unflattenFromString("a/a"), 0, false,
                mock(ServiceConnection.class), 26);
        ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo(
                iInterface, ComponentName.unflattenFromString("b/b"), 10, false,
                mock(ServiceConnection.class), 26);
        Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
        removableBoundServices.add(service0);
        removableBoundServices.add(service10);

        SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>();
        Set<ComponentName> allowed0 = new ArraySet<>();
        allowed0.add(ComponentName.unflattenFromString("a/a"));
        allowedComponentsToBind.put(0, allowed0);
        Set<ComponentName> allowed10 = new ArraySet<>();
        allowed10.add(ComponentName.unflattenFromString("b/b"));
        allowedComponentsToBind.put(10, allowed10);

        SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();

        service.populateComponentsToUnbind(true, removableBoundServices, allowedComponentsToBind,
                componentsToUnbind);

        assertEquals(2, componentsToUnbind.size());
        assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("a/a")));
        assertTrue(componentsToUnbind.get(10).contains(ComponentName.unflattenFromString("b/b")));
    }

    @Test
    public void testPopulateComponentsToUnbind() {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);

        IInterface iInterface = mock(IInterface.class);
        when(iInterface.asBinder()).thenReturn(mock(IBinder.class));

        ManagedServices.ManagedServiceInfo service0 = service.new ManagedServiceInfo(
                iInterface, ComponentName.unflattenFromString("a/a"), 0, false,
                mock(ServiceConnection.class), 26);
        ManagedServices.ManagedServiceInfo service0a = service.new ManagedServiceInfo(
                iInterface, ComponentName.unflattenFromString("c/c"), 0, false,
                mock(ServiceConnection.class), 26);
        ManagedServices.ManagedServiceInfo service10 = service.new ManagedServiceInfo(
                iInterface, ComponentName.unflattenFromString("b/b"), 10, false,
                mock(ServiceConnection.class), 26);
        Set<ManagedServices.ManagedServiceInfo> removableBoundServices = new ArraySet<>();
        removableBoundServices.add(service0);
        removableBoundServices.add(service0a);
        removableBoundServices.add(service10);

        SparseArray<Set<ComponentName>> allowedComponentsToBind = new SparseArray<>();
        Set<ComponentName> allowed0 = new ArraySet<>();
        allowed0.add(ComponentName.unflattenFromString("a/a"));
        allowedComponentsToBind.put(0, allowed0);
        Set<ComponentName> allowed10 = new ArraySet<>();
        allowed10.add(ComponentName.unflattenFromString("b/b"));
        allowedComponentsToBind.put(10, allowed10);

        SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();

        service.populateComponentsToUnbind(false, removableBoundServices, allowedComponentsToBind,
                componentsToUnbind);

        assertEquals(1, componentsToUnbind.size());
        assertEquals(1, componentsToUnbind.get(0).size());
        assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("c/c")));
    }

    @Test
    public void populateComponentsToBind() {
        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);

        SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>();
        ArraySet<ComponentName> allowed0 = new ArraySet<>();
        allowed0.add(ComponentName.unflattenFromString("a/a"));
        approvedComponentsByUser.put(0, allowed0);
        ArraySet<ComponentName> allowed10 = new ArraySet<>();
        allowed10.add(ComponentName.unflattenFromString("b/b"));
        allowed10.add(ComponentName.unflattenFromString("c/c"));
        approvedComponentsByUser.put(10, allowed10);
        ArraySet<ComponentName> allowed15 = new ArraySet<>();
        allowed15.add(ComponentName.unflattenFromString("d/d"));
        approvedComponentsByUser.put(15, allowed15);

        IntArray users = new IntArray();
        users.add(10);
        users.add(0);

        SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();

        service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser);

        assertEquals(2, componentsToBind.size());
        assertEquals(1, componentsToBind.get(0).size());
        assertTrue(componentsToBind.get(0).contains(ComponentName.unflattenFromString("a/a")));
        assertEquals(2, componentsToBind.get(10).size());
        assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("b/b")));
        assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
    }

    @Test
    public void testOnNullBinding() throws Exception {
        Context context = mock(Context.class);
        PackageManager pm = mock(PackageManager.class);
        ApplicationInfo ai = new ApplicationInfo();
        ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;

        when(context.getPackageName()).thenReturn(mContext.getPackageName());
        when(context.getUserId()).thenReturn(mContext.getUserId());
        when(context.getPackageManager()).thenReturn(pm);
        when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);

        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);
        ComponentName cn = ComponentName.unflattenFromString("a/a");

        service.registerSystemService(cn, 0);
        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
            Object[] args = invocation.getArguments();
            ServiceConnection sc = (ServiceConnection) args[1];
            sc.onNullBinding(cn);
            return true;
        });

        service.registerSystemService(cn, 0);
        assertFalse(service.isBound(cn, 0));
    }

    @Test
    public void testOnServiceConnected() throws Exception {
        Context context = mock(Context.class);
        PackageManager pm = mock(PackageManager.class);
        ApplicationInfo ai = new ApplicationInfo();
        ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;

        when(context.getPackageName()).thenReturn(mContext.getPackageName());
        when(context.getUserId()).thenReturn(mContext.getUserId());
        when(context.getPackageManager()).thenReturn(pm);
        when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);

        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
                APPROVAL_BY_COMPONENT);
        ComponentName cn = ComponentName.unflattenFromString("a/a");

        service.registerSystemService(cn, 0);
        when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
            Object[] args = invocation.getArguments();
            ServiceConnection sc = (ServiceConnection) args[1];
            sc.onServiceConnected(cn, mock(IBinder.class));
            return true;
        });

        service.registerSystemService(cn, 0);
        assertTrue(service.isBound(cn, 0));
    }

    @Test
    public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            // null uid list
            service.onPackagesChanged(true, new String[]{"this.is.a.package.name"}, null);

            // null package list
            service.onPackagesChanged(true, null, new int[]{103});
        }
    }

    private void loadXml(ManagedServices service) throws Exception {
        final StringBuffer xml = new StringBuffer();
        xml.append("<" + service.getConfig().xmlTag + ">\n");
        for (int userId : mExpectedPrimary.get(service.mApprovalLevel).keySet()) {
            xml.append(getXmlEntry(
                    mExpectedPrimary.get(service.mApprovalLevel).get(userId), userId, true));
        }
        for (int userId : mExpectedSecondary.get(service.mApprovalLevel).keySet()) {
            xml.append(getXmlEntry(
                    mExpectedSecondary.get(service.mApprovalLevel).get(userId), userId, false));
        }
        xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                        + ManagedServices.ATT_USER_ID + "=\"99\" "
                        + ManagedServices.ATT_IS_PRIMARY + "=\"true\" "
                        + ManagedServices.ATT_APPROVED_LIST + "=\"99\" />\n");
        xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                + ManagedServices.ATT_USER_ID + "=\"98\" "
                + ManagedServices.ATT_IS_PRIMARY + "=\"false\" "
                + ManagedServices.ATT_APPROVED_LIST + "=\"98\" />\n");
        xml.append("</" + service.getConfig().xmlTag + ">");

        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(
                new ByteArrayInputStream(xml.toString().getBytes())), null);
        parser.nextTag();
        service.readXml(parser, null, false, UserHandle.USER_ALL);
    }

    private XmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
            throws Exception {
        final StringBuffer xml = new StringBuffer();
        xml.append("<" + service.getConfig().xmlTag + ">\n");
        for (String xmlEntry : xmlEntries) {
            xml.append(xmlEntry);
        }
        xml.append("</" + service.getConfig().xmlTag + ">");

        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(
                new ByteArrayInputStream(xml.toString().getBytes())), null);
        parser.nextTag();
        return parser;
    }

    private void addExpectedServices(final ManagedServices service, final List<String> packages,
            int userId) {
        when(mPm.queryIntentServicesAsUser(any(), anyInt(), eq(userId))).
                thenAnswer(new Answer<List<ResolveInfo>>() {
                    @Override
                    public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
                            throws Throwable {
                        Object[] args = invocationOnMock.getArguments();
                        Intent invocationIntent = (Intent) args[0];
                        if (invocationIntent != null) {
                            if (invocationIntent.getAction().equals(
                                    service.getConfig().serviceInterface)
                                    && packages.contains(invocationIntent.getPackage())) {
                                List<ResolveInfo> dummyServices = new ArrayList<>();
                                for (int i = 1; i <= 3; i ++) {
                                    ResolveInfo resolveInfo = new ResolveInfo();
                                    ServiceInfo serviceInfo = new ServiceInfo();
                                    serviceInfo.packageName = invocationIntent.getPackage();
                                    serviceInfo.name = "C"+i;
                                    serviceInfo.permission = service.getConfig().bindPermission;
                                    resolveInfo.serviceInfo = serviceInfo;
                                    dummyServices.add(resolveInfo);
                                }
                                return dummyServices;
                            }
                        }
                        return new ArrayList<>();
                    }
                });
    }

    private List<String> stringToList(String list) {
        if (list == null) {
            list = "";
        }
        return new ArrayList<>(Lists.newArrayList(list.split(
                ManagedServices.ENABLED_SERVICES_SEPARATOR)));
    }

    private void assertContentsInAnyOrder(Collection<?> expected, Collection<?> actual) {
        assertNotNull(actual);
        assertEquals(expected.size(), actual.size());

        for (Object o : expected) {
            assertTrue("Actual missing " + o, actual.contains(o));
        }

        for (Object o : actual) {
            assertTrue("Actual contains extra " + o, expected.contains(o));
        }
    }

    private void assertContentsInAnyOrder(SparseArray<ArraySet<ComponentName>> expected,
            SparseArray<ArraySet<ComponentName>> actual) throws Exception {
        assertEquals(expected.size(), actual.size());

        for (int i = 0; i < expected.size(); i++) {
            int key = expected.keyAt(i);
            assertTrue(actual.indexOfKey(key) >= 0);
            try {
                assertContentsInAnyOrder(expected.valueAt(i), actual.get(key));
            } catch (Throwable t) {
                throw new Exception("Error validating " + key, t);
            }
        }
    }

    private void verifyExpectedBoundEntries(ManagedServices service, boolean primary)
            throws Exception {
        ArrayMap<Integer, String> verifyMap = primary ? mExpectedPrimary.get(service.mApprovalLevel)
                : mExpectedSecondary.get(service.mApprovalLevel);
        for (int userId : verifyMap.keySet()) {
            for (String packageOrComponent : verifyMap.get(userId).split(":")) {
                if (!TextUtils.isEmpty(packageOrComponent)) {
                    if (service.mApprovalLevel == APPROVAL_BY_PACKAGE) {
                        assertTrue(packageOrComponent,
                                service.isComponentEnabledForPackage(packageOrComponent));
                        for (int i = 1; i <= 3; i++) {
                            ComponentName componentName = ComponentName.unflattenFromString(
                                    packageOrComponent +"/C" + i);
                            assertTrue(service.isComponentEnabledForCurrentProfiles(
                                    componentName));
                            verify(mIpm, times(1)).getServiceInfo(
                                    eq(componentName), anyInt(), anyInt());
                        }
                    } else {
                        ComponentName componentName =
                                ComponentName.unflattenFromString(packageOrComponent);
                        assertTrue(service.isComponentEnabledForCurrentProfiles(componentName));
                        verify(mIpm, times(1)).getServiceInfo(
                                eq(componentName), anyInt(), anyInt());
                    }
                }
            }
        }
    }

    private void verifyExpectedApprovedEntries(ManagedServices service) {
        verifyExpectedApprovedEntries(service, true);
        verifyExpectedApprovedEntries(service, false);
    }

    private void verifyExpectedApprovedEntries(ManagedServices service, boolean primary) {
        ArrayMap<Integer, String> verifyMap = primary
                ? mExpectedPrimary.get(service.mApprovalLevel)
                : mExpectedSecondary.get(service.mApprovalLevel);
        verifyExpectedApprovedEntries(service, verifyMap);
    }

    private void verifyExpectedApprovedEntries(ManagedServices service,
            ArrayMap<Integer, String> verifyMap) {
        for (int userId : verifyMap.keySet()) {
            for (String verifyValue : verifyMap.get(userId).split(":")) {
                if (!TextUtils.isEmpty(verifyValue)) {
                    assertTrue("service type " + service.mApprovalLevel + ":"
                                    + verifyValue + " is not allowed for user " + userId,
                            service.isPackageOrComponentAllowed(verifyValue, userId));
                }
            }
        }
    }


    private void verifyExpectedApprovedPackages(ManagedServices service) {
        verifyExpectedApprovedPackages(service, true);
        verifyExpectedApprovedPackages(service, false);
    }

    private void verifyExpectedApprovedPackages(ManagedServices service, boolean primary) {
        ArrayMap<Integer, String> verifyMap = primary
                ? mExpectedPrimary.get(service.mApprovalLevel)
                : mExpectedSecondary.get(service.mApprovalLevel);
        verifyExpectedApprovedPackages(service, verifyMap);
    }

    private void verifyExpectedApprovedPackages(ManagedServices service,
            ArrayMap<Integer, String> verifyMap) {
        for (int userId : verifyMap.keySet()) {
            for (String verifyValue : verifyMap.get(userId).split(":")) {
                if (!TextUtils.isEmpty(verifyValue)) {
                    ComponentName component = ComponentName.unflattenFromString(verifyValue);
                    if (component != null ) {
                        assertTrue("service type " + service.mApprovalLevel + ":"
                                        + verifyValue + " is not allowed for user " + userId,
                                service.isPackageAllowed(component.getPackageName(), userId));
                    } else {
                        assertTrue("service type " + service.mApprovalLevel + ":"
                                        + verifyValue + " is not allowed for user " + userId,
                                service.isPackageAllowed(verifyValue, userId));
                    }
                }
            }
        }
    }

    private void writeExpectedValuesToSettings(int approvalLevel) {
        for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
            Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING,
                    mExpectedPrimary.get(approvalLevel).get(userId), userId);
        }
        for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
            Settings.Secure.putStringForUser(getContext().getContentResolver(), SECONDARY_SETTING,
                    mExpectedSecondary.get(approvalLevel).get(userId), userId);
        }
    }

    private String getXmlEntry(String approved, int userId, boolean isPrimary) {
        return "<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                + ManagedServices.ATT_USER_ID + "=\"" + userId +"\" "
                + ManagedServices.ATT_IS_PRIMARY + "=\"" + isPrimary +"\" "
                + ManagedServices.ATT_APPROVED_LIST + "=\"" + approved +"\" "
                + "/>\n";
    }

    class TestManagedServices extends ManagedServices {

        public TestManagedServices(Context context, Object mutex, UserProfiles userProfiles,
                IPackageManager pm, int approvedServiceType) {
            super(context, mutex, userProfiles, pm);
            mApprovalLevel = approvedServiceType;
        }

        @Override
        protected Config getConfig() {
            final Config c = new Config();
            c.xmlTag = "test";
            c.secureSettingName = SETTING;
            c.secondarySettingName = SECONDARY_SETTING;
            c.bindPermission = "permission";
            c.serviceInterface = "serviceInterface";
            return c;
        }

        @Override
        protected IInterface asInterface(IBinder binder) {
            return null;
        }

        @Override
        protected boolean checkType(IInterface service) {
            return true;
        }

        @Override
        protected void onServiceAdded(ManagedServiceInfo info) {

        }

        @Override
        protected String getRequiredPermission() {
            return null;
        }
    }
}
