19e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov/* 29e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Copyright (C) 2015 The Android Open Source Project 39e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * 49e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Licensed under the Apache License, Version 2.0 (the "License"); 59e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * you may not use this file except in compliance with the License. 69e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * You may obtain a copy of the License at 79e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * 89e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * http://www.apache.org/licenses/LICENSE-2.0 99e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * 109e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Unless required by applicable law or agreed to in writing, software 119e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * distributed under the License is distributed on an "AS IS" BASIS, 129e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * See the License for the specific language governing permissions and 149e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * limitations under the License 159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov */ 169e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 179e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovpackage android.content.pm; 189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 199e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.content.res.Resources; 209e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.FileUtils; 219e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.Parcel; 229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.Parcelable; 239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.os.UserHandle; 249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.test.AndroidTestCase; 259e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.util.AttributeSet; 269e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport android.util.SparseArray; 279e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 289e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport org.xmlpull.v1.XmlPullParser; 299e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport org.xmlpull.v1.XmlPullParserException; 309e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport org.xmlpull.v1.XmlSerializer; 319e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 32259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolovimport java.io.ByteArrayInputStream; 339e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.io.File; 349e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.io.IOException; 359e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.ArrayList; 369e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.Collection; 379e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.HashMap; 389e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.HashSet; 399e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.List; 409e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.Map; 419e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovimport java.util.Set; 429e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 439e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov/** 449e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Tests for {@link android.content.pm.RegisteredServicesCache} 459e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov */ 469e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolovpublic class RegisteredServicesCacheTest extends AndroidTestCase { 47259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private static final int U0 = 0; 48259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private static final int U1 = 1; 49259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private static final int UID1 = 1; 50259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private static final int UID2 = 2; 51259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Represents UID of a system image process 52259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private static final int SYSTEM_IMAGE_UID = 20; 539e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 549e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final ResolveInfo r1 = new ResolveInfo(); 559e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final ResolveInfo r2 = new ResolveInfo(); 569e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final TestServiceType t1 = new TestServiceType("t1", "value1"); 579e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private final TestServiceType t2 = new TestServiceType("t2", "value2"); 589e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private File mDataDir; 599e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private File mSyncDir; 60259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private List<UserInfo> mUsers; 619e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 629e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 639e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected void setUp() throws Exception { 649e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov super.setUp(); 659e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov File cacheDir = mContext.getCacheDir(); 669e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mDataDir = new File(cacheDir, "testServicesCache"); 679e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov FileUtils.deleteContents(mDataDir); 68259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov mSyncDir = new File(mDataDir, "system/"+RegisteredServicesCache.REGISTERED_SERVICES_DIR); 699e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mSyncDir.mkdirs(); 70259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov mUsers = new ArrayList<>(); 71259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov mUsers.add(new UserInfo(0, "Owner", UserInfo.FLAG_ADMIN)); 72259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov mUsers.add(new UserInfo(1, "User1", 0)); 739e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 749e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 759e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesHappyPath() { 76259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServicesCache cache = new TestServicesCache(); 77259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 78259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2)); 79259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getAllServicesSize(U0)); 80259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(U0)); 81259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertNotEmptyFileCreated(cache, U0); 829e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Make sure all services can be loaded from xml 83259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache = new TestServicesCache(); 84259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(U0)); 859e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 869e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 879e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesReplaceUid() { 88259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServicesCache cache = new TestServicesCache(); 89259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 90259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2)); 91259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.getAllServices(U0); 929e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Invalidate cache and clear update query results 93259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.invalidateCache(U0); 949e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov cache.clearServicesForQuerying(); 95259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 96259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, SYSTEM_IMAGE_UID)); 979e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Collection<RegisteredServicesCache.ServiceInfo<TestServiceType>> allServices = cache 98259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov .getAllServices(U0); 999e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals(2, allServices.size()); 1009e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Set<Integer> uids = new HashSet<>(); 1019e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov for (RegisteredServicesCache.ServiceInfo<TestServiceType> srv : allServices) { 1029e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov uids.add(srv.uid); 1039e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1049e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertTrue("UID must be updated to the new value", 105259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov uids.contains(SYSTEM_IMAGE_UID)); 106259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertFalse("UID must be updated to the new value", uids.contains(UID2)); 1079e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1089e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1099e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesServiceRemoved() { 110259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServicesCache cache = new TestServicesCache(); 111259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 112259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2)); 113259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getAllServicesSize(U0)); 114259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(U0)); 1159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Re-read data from disk and verify services were saved 116259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache = new TestServicesCache(); 117259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(U0)); 1189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Now register only one service and verify that another one is removed 119259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 120259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getAllServicesSize(U0)); 121259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(U0)); 1229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 1239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 1249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void testGetAllServicesMultiUser() { 125259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServicesCache cache = new TestServicesCache(); 126259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 127259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov int u1uid = UserHandle.getUid(U1, 0); 128259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U1, r2, newServiceInfo(t2, u1uid)); 129259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getAllServicesSize(U0)); 130259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(U0)); 131259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getAllServicesSize(U1)); 132259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(U1)); 1339e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov assertEquals("No services should be available for user 3", 0, cache.getAllServicesSize(3)); 1349e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov // Re-read data from disk and verify services were saved 135259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache = new TestServicesCache(); 136259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(U0)); 137259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(U1)); 138259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertNotEmptyFileCreated(cache, U0); 139259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertNotEmptyFileCreated(cache, U1); 140259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 141259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 142259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov public void testOnRemove() { 143259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServicesCache cache = new TestServicesCache(); 144259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1)); 145259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov int u1uid = UserHandle.getUid(U1, 0); 146259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(U1, r2, newServiceInfo(t2, u1uid)); 147259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getAllServicesSize(U0)); 148259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getAllServicesSize(U1)); 149259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Simulate ACTION_USER_REMOVED 150259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.onUserRemoved(U1); 151259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Make queryIntentServices(u1) return no results for U1 152259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.clearServicesForQuerying(); 153259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getAllServicesSize(U0)); 154259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(0, cache.getAllServicesSize(U1)); 155259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 156259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 157259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov public void testMigration() { 158259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Prepare "old" file for testing 159259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov String oldFile = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 160259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov + "<services>\n" 161259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov + " <service uid=\"1\" type=\"type1\" value=\"value1\" />\n" 162259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov + " <service uid=\"100002\" type=\"type2\" value=\"value2\" />\n" 163259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov + "<services>\n"; 164259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 165259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov File file = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml"); 166259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov FileUtils.copyToFile(new ByteArrayInputStream(oldFile.getBytes()), file); 167259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 168259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov int u0 = 0; 169259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov int u1 = 1; 170259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServicesCache cache = new TestServicesCache(); 171259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(u0)); 172259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(1, cache.getPersistentServicesSize(u1)); 173259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertNotEmptyFileCreated(cache, u0); 174259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertNotEmptyFileCreated(cache, u1); 175259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Check that marker was created 176259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov File markerFile = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml.migrated"); 177259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertTrue("Marker file should be created at " + markerFile, markerFile.exists()); 178259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Now introduce 2 service types for u0: t1, t2. type1 will be removed 179259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(0, r1, newServiceInfo(t1, 1)); 180259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache.addServiceForQuerying(0, r2, newServiceInfo(t2, 2)); 181259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getAllServicesSize(u0)); 182259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(0, cache.getAllServicesSize(u1)); 183259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov // Re-read data from disk. Verify that services were saved and old file was ignored 184259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov cache = new TestServicesCache(); 185259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(2, cache.getPersistentServicesSize(u0)); 186259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertEquals(0, cache.getPersistentServicesSize(u1)); 187259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 188259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 189259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private static RegisteredServicesCache.ServiceInfo<TestServiceType> newServiceInfo( 190259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov TestServiceType type, int uid) { 191259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov return new RegisteredServicesCache.ServiceInfo<>(type, null, uid); 192259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 193259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 194259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private void assertNotEmptyFileCreated(TestServicesCache cache, int userId) { 195259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov File dir = new File(cache.getUserSystemDirectory(userId), 196259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov RegisteredServicesCache.REGISTERED_SERVICES_DIR); 197259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov File file = new File(dir, TestServicesCache.SERVICE_INTERFACE+".xml"); 198259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov assertTrue("File should be created at " + file, file.length() > 0); 1999e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2009e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2019e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov /** 2029e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov * Mock implementation of {@link android.content.pm.RegisteredServicesCache} for testing 2039e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov */ 204259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov private class TestServicesCache extends RegisteredServicesCache<TestServiceType> { 2059e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final String SERVICE_INTERFACE = "RegisteredServicesCacheTest"; 2069e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final String SERVICE_META_DATA = "RegisteredServicesCacheTest"; 2079e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static final String ATTRIBUTES_NAME = "test"; 2089e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov private SparseArray<Map<ResolveInfo, ServiceInfo<TestServiceType>>> mServices 2099e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov = new SparseArray<>(); 2109e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 211259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov public TestServicesCache() { 212259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov super(RegisteredServicesCacheTest.this.mContext, 213259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, new TestSerializer()); 2149e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2169e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2179e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType parseServiceAttributes(Resources res, String packageName, 2189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov AttributeSet attrs) { 2199e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return null; 2209e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2219e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected List<ResolveInfo> queryIntentServices(int userId) { 2249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices 2259e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov .get(userId, new HashMap<ResolveInfo, ServiceInfo<TestServiceType>>()); 2269e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new ArrayList<>(map.keySet()); 2279e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2289e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 229259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov @Override 230259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov protected File getUserSystemDirectory(int userId) { 231259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov File dir = new File(mDataDir, "users/" + userId); 232259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov dir.mkdirs(); 233259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov return dir; 234259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 235259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 236259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov @Override 237259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov protected List<UserInfo> getUsers() { 238259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov return mUsers; 239259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 240259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 241259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov @Override 242259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov protected UserInfo getUser(int userId) { 243259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov for (UserInfo user : getUsers()) { 244259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov if (user.id == userId) { 245259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov return user; 246259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 247259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 248259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov return null; 249259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 250259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 251259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov @Override 252259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov protected File getDataDirectory() { 253259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov return mDataDir; 254259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 255259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 2569e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov void addServiceForQuerying(int userId, ResolveInfo resolveInfo, 2579e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ServiceInfo<TestServiceType> serviceInfo) { 2589e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.get(userId); 2599e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (map == null) { 2609e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov map = new HashMap<>(); 2619e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mServices.put(userId, map); 2629e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2639e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov map.put(resolveInfo, serviceInfo); 2649e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2659e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2669e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov void clearServicesForQuerying() { 2679e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov mServices.clear(); 2689e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2699e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2709e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int getPersistentServicesSize(int user) { 2719e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return getPersistentServices(user).size(); 2729e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2739e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2749e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int getAllServicesSize(int user) { 2759e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return getAllServices(user).size(); 2769e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2779e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2789e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2799e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected boolean inSystemImage(int callerUid) { 2809e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return callerUid == SYSTEM_IMAGE_UID; 2819e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2829e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 2839e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 2849e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov protected ServiceInfo<TestServiceType> parseServiceInfo( 2859e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ResolveInfo resolveInfo) throws XmlPullParserException, IOException { 2869e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov int size = mServices.size(); 2879e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov for (int i = 0; i < size; i++) { 2889e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i); 2899e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ServiceInfo<TestServiceType> serviceInfo = map.get(resolveInfo); 2909e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (serviceInfo != null) { 2919e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return serviceInfo; 2929e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2939e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 2949e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov throw new IllegalArgumentException("Unexpected service " + resolveInfo); 2959e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 296259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov 297259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov @Override 298259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov public void onUserRemoved(int userId) { 299259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov super.onUserRemoved(userId); 300259e76153255e4d7c6d6c14af77936fe060e7038Fyodor Kupolov } 3019e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3029e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3039e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static class TestSerializer implements XmlSerializerAndParser<TestServiceType> { 3049e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3059e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException { 3069e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov out.attribute(null, "type", item.type); 3079e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov out.attribute(null, "value", item.value); 3089e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3099e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3109e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType createFromXml(XmlPullParser parser) 3119e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov throws IOException, XmlPullParserException { 3129e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String type = parser.getAttributeValue(null, "type"); 3139e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String value = parser.getAttributeValue(null, "value"); 3149e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new TestServiceType(type, value); 3159e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3169e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3179e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3189e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov static class TestServiceType implements Parcelable { 3199e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String type; 3209e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov final String value; 3219e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3229e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType(String type, String value) { 3239e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov this.type = type; 3249e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov this.value = value; 3259e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3269e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3279e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 3289e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public boolean equals(Object o) { 3299e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (this == o) { 3309e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return true; 3319e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3329e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov if (o == null || getClass() != o.getClass()) { 3339e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return false; 3349e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3359e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3369e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov TestServiceType that = (TestServiceType) o; 3379e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3389e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return type.equals(that.type) && value.equals(that.value); 3399e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3409e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3419e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 3429e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public int hashCode() { 3439e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return 31 * type.hashCode() + value.hashCode(); 3449e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3459e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3469e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov @Override 3479e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public String toString() { 3489e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return "TestServiceType{" + 3499e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov "type='" + type + '\'' + 3509e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov ", value='" + value + '\'' + 3519e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov '}'; 3529e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3539e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3549e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public int describeContents() { 3559e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return 0; 3569e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3579e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3589e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public void writeToParcel(Parcel dest, int flags) { 3599e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov dest.writeString(type); 3609e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov dest.writeString(value); 3619e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3629e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3639e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType(Parcel source) { 3649e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov this(source.readString(), source.readString()); 3659e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3669e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3679e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public static final Creator<TestServiceType> CREATOR = new Creator<TestServiceType>() { 3689e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType createFromParcel(Parcel source) { 3699e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new TestServiceType(source); 3709e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3719e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov 3729e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov public TestServiceType[] newArray(int size) { 3739e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov return new TestServiceType[size]; 3749e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3759e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov }; 3769e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov } 3779e0d81e8439089845b7ddee21676f3f427a34ccaFyodor Kupolov} 378