RegisteredServicesCacheTest.java revision 9e0d81e8439089845b7ddee21676f3f427a34cca
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package android.content.pm; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.os.FileUtils; 22import android.os.Parcel; 23import android.os.Parcelable; 24import android.os.UserHandle; 25import android.test.AndroidTestCase; 26import android.util.AttributeSet; 27import android.util.SparseArray; 28 29import org.xmlpull.v1.XmlPullParser; 30import org.xmlpull.v1.XmlPullParserException; 31import org.xmlpull.v1.XmlSerializer; 32 33import java.io.File; 34import java.io.IOException; 35import java.util.ArrayList; 36import java.util.Collection; 37import java.util.HashMap; 38import java.util.HashSet; 39import java.util.List; 40import java.util.Map; 41import java.util.Set; 42 43/** 44 * Tests for {@link android.content.pm.RegisteredServicesCache} 45 */ 46public class RegisteredServicesCacheTest extends AndroidTestCase { 47 48 private final ResolveInfo r1 = new ResolveInfo(); 49 private final ResolveInfo r2 = new ResolveInfo(); 50 private final TestServiceType t1 = new TestServiceType("t1", "value1"); 51 private final TestServiceType t2 = new TestServiceType("t2", "value2"); 52 private File mDataDir; 53 private File mSyncDir; 54 55 @Override 56 protected void setUp() throws Exception { 57 super.setUp(); 58 File cacheDir = mContext.getCacheDir(); 59 mDataDir = new File(cacheDir, "testServicesCache"); 60 FileUtils.deleteContents(mDataDir); 61 mSyncDir = new File(mDataDir, "system/registered_services"); 62 mSyncDir.mkdirs(); 63 } 64 65 public void testGetAllServicesHappyPath() { 66 TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 67 cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 68 cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2)); 69 assertEquals(2, cache.getAllServicesSize(0)); 70 assertEquals(2, cache.getPersistentServicesSize(0)); 71 File file = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml"); 72 assertTrue("File should be created at " + file, file.length() > 0); 73 // Make sure all services can be loaded from xml 74 cache = new TestServicesCache(mContext, mDataDir); 75 assertEquals(2, cache.getPersistentServicesSize(0)); 76 } 77 78 public void testGetAllServicesReplaceUid() { 79 TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 80 cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 81 cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2)); 82 cache.getAllServices(0); 83 // Invalidate cache and clear update query results 84 cache.invalidateCache(0); 85 cache.clearServicesForQuerying(); 86 cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 87 cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 88 TestServicesCache.SYSTEM_IMAGE_UID)); 89 Collection<RegisteredServicesCache.ServiceInfo<TestServiceType>> allServices = cache 90 .getAllServices(0); 91 assertEquals(2, allServices.size()); 92 Set<Integer> uids = new HashSet<>(); 93 for (RegisteredServicesCache.ServiceInfo<TestServiceType> srv : allServices) { 94 uids.add(srv.uid); 95 } 96 assertTrue("UID must be updated to the new value", 97 uids.contains(TestServicesCache.SYSTEM_IMAGE_UID)); 98 assertFalse("UID must be updated to the new value", uids.contains(2)); 99 } 100 101 public void testGetAllServicesServiceRemoved() { 102 TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 103 cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 104 cache.addServiceForQuerying(0, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 2)); 105 assertEquals(2, cache.getAllServicesSize(0)); 106 assertEquals(2, cache.getPersistentServicesSize(0)); 107 // Re-read data from disk and verify services were saved 108 cache = new TestServicesCache(mContext, mDataDir); 109 assertEquals(2, cache.getPersistentServicesSize(0)); 110 // Now register only one service and verify that another one is removed 111 cache.addServiceForQuerying(0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 1)); 112 assertEquals(1, cache.getAllServicesSize(0)); 113 assertEquals(1, cache.getPersistentServicesSize(0)); 114 } 115 116 public void testGetAllServicesMultiUser() { 117 TestServicesCache cache = new TestServicesCache(mContext, mDataDir); 118 int u0 = 0; 119 int u1 = 1; 120 int pid1 = 1; 121 cache.addServiceForQuerying(u0, r1, new RegisteredServicesCache.ServiceInfo<>(t1, null, 122 pid1)); 123 int u1uid = UserHandle.getUid(u1, 0); 124 cache.addServiceForQuerying(u1, r2, new RegisteredServicesCache.ServiceInfo<>(t2, null, 125 u1uid)); 126 assertEquals(u1, cache.getAllServicesSize(u0)); 127 assertEquals(u1, cache.getPersistentServicesSize(u0)); 128 assertEquals(u1, cache.getAllServicesSize(u1)); 129 assertEquals(u1, cache.getPersistentServicesSize(u1)); 130 assertEquals("No services should be available for user 3", 0, cache.getAllServicesSize(3)); 131 // Re-read data from disk and verify services were saved 132 cache = new TestServicesCache(mContext, mDataDir); 133 assertEquals(u1, cache.getPersistentServicesSize(u0)); 134 assertEquals(u1, cache.getPersistentServicesSize(u1)); 135 } 136 137 /** 138 * Mock implementation of {@link android.content.pm.RegisteredServicesCache} for testing 139 */ 140 private static class TestServicesCache extends RegisteredServicesCache<TestServiceType> { 141 static final String SERVICE_INTERFACE = "RegisteredServicesCacheTest"; 142 static final String SERVICE_META_DATA = "RegisteredServicesCacheTest"; 143 static final String ATTRIBUTES_NAME = "test"; 144 // Represents UID of a system image process 145 static final int SYSTEM_IMAGE_UID = 20; 146 private SparseArray<Map<ResolveInfo, ServiceInfo<TestServiceType>>> mServices 147 = new SparseArray<>(); 148 149 public TestServicesCache(Context context, File dir) { 150 super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, 151 new TestSerializer(), dir); 152 } 153 154 @Override 155 public TestServiceType parseServiceAttributes(Resources res, String packageName, 156 AttributeSet attrs) { 157 return null; 158 } 159 160 @Override 161 protected List<ResolveInfo> queryIntentServices(int userId) { 162 Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices 163 .get(userId, new HashMap<ResolveInfo, ServiceInfo<TestServiceType>>()); 164 return new ArrayList<>(map.keySet()); 165 } 166 167 void addServiceForQuerying(int userId, ResolveInfo resolveInfo, 168 ServiceInfo<TestServiceType> serviceInfo) { 169 Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.get(userId); 170 if (map == null) { 171 map = new HashMap<>(); 172 mServices.put(userId, map); 173 } 174 map.put(resolveInfo, serviceInfo); 175 } 176 177 void clearServicesForQuerying() { 178 mServices.clear(); 179 } 180 181 int getPersistentServicesSize(int user) { 182 return getPersistentServices(user).size(); 183 } 184 185 int getAllServicesSize(int user) { 186 return getAllServices(user).size(); 187 } 188 189 @Override 190 protected boolean inSystemImage(int callerUid) { 191 return callerUid == SYSTEM_IMAGE_UID; 192 } 193 194 @Override 195 protected ServiceInfo<TestServiceType> parseServiceInfo( 196 ResolveInfo resolveInfo) throws XmlPullParserException, IOException { 197 int size = mServices.size(); 198 for (int i = 0; i < size; i++) { 199 Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i); 200 ServiceInfo<TestServiceType> serviceInfo = map.get(resolveInfo); 201 if (serviceInfo != null) { 202 return serviceInfo; 203 } 204 } 205 throw new IllegalArgumentException("Unexpected service " + resolveInfo); 206 } 207 } 208 209 static class TestSerializer implements XmlSerializerAndParser<TestServiceType> { 210 211 public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException { 212 out.attribute(null, "type", item.type); 213 out.attribute(null, "value", item.value); 214 } 215 216 public TestServiceType createFromXml(XmlPullParser parser) 217 throws IOException, XmlPullParserException { 218 final String type = parser.getAttributeValue(null, "type"); 219 final String value = parser.getAttributeValue(null, "value"); 220 return new TestServiceType(type, value); 221 } 222 } 223 224 static class TestServiceType implements Parcelable { 225 final String type; 226 final String value; 227 228 public TestServiceType(String type, String value) { 229 this.type = type; 230 this.value = value; 231 } 232 233 @Override 234 public boolean equals(Object o) { 235 if (this == o) { 236 return true; 237 } 238 if (o == null || getClass() != o.getClass()) { 239 return false; 240 } 241 242 TestServiceType that = (TestServiceType) o; 243 244 return type.equals(that.type) && value.equals(that.value); 245 } 246 247 @Override 248 public int hashCode() { 249 return 31 * type.hashCode() + value.hashCode(); 250 } 251 252 @Override 253 public String toString() { 254 return "TestServiceType{" + 255 "type='" + type + '\'' + 256 ", value='" + value + '\'' + 257 '}'; 258 } 259 260 public int describeContents() { 261 return 0; 262 } 263 264 public void writeToParcel(Parcel dest, int flags) { 265 dest.writeString(type); 266 dest.writeString(value); 267 } 268 269 public TestServiceType(Parcel source) { 270 this(source.readString(), source.readString()); 271 } 272 273 public static final Creator<TestServiceType> CREATOR = new Creator<TestServiceType>() { 274 public TestServiceType createFromParcel(Parcel source) { 275 return new TestServiceType(source); 276 } 277 278 public TestServiceType[] newArray(int size) { 279 return new TestServiceType[size]; 280 } 281 }; 282 } 283} 284