1/* 2 * Copyright (C) 2016 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 com.android.cellbroadcastreceiver; 18 19import android.os.IBinder; 20import android.os.ServiceManager; 21import android.util.Log; 22 23import java.lang.reflect.Field; 24import java.util.HashMap; 25import java.util.Iterator; 26import java.util.LinkedList; 27 28// This class is for replacing existing system service with the mocked service. 29public final class MockedServiceManager { 30 31 private final String TAG = MockedServiceManager.class.getSimpleName(); 32 33 private final HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>(); 34 35 private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>(); 36 37 private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>(); 38 39 private static class InstanceKey { 40 final Class mClass; 41 final String mInstName; 42 final Object mObj; 43 44 InstanceKey(final Class c, final String instName, final Object obj) { 45 mClass = c; 46 mInstName = instName; 47 mObj = obj; 48 } 49 50 @Override 51 public int hashCode() { 52 return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31; 53 } 54 55 @Override 56 public boolean equals(Object obj) { 57 if (obj == null || obj.getClass() != getClass()) { 58 return false; 59 } 60 61 InstanceKey other = (InstanceKey) obj; 62 return (other.mClass == mClass && other.mInstName.equals(mInstName) 63 && other.mObj == mObj); 64 } 65 } 66 67 MockedServiceManager() throws Exception { 68 replaceInstance(ServiceManager.class, "sCache", null, mServiceManagerMockedServices); 69 } 70 71 void replaceService(String key, IBinder binder) { 72 mServiceManagerMockedServices.put(key, binder); 73 } 74 75 void restoreAllServices() throws Exception { 76 restoreInstances(); 77 } 78 79 private synchronized void replaceInstance(final Class c, final String instanceName, 80 final Object obj, final Object newValue) 81 throws Exception { 82 Field field = c.getDeclaredField(instanceName); 83 field.setAccessible(true); 84 85 InstanceKey key = new InstanceKey(c, instanceName, obj); 86 if (!mOldInstances.containsKey(key)) { 87 mOldInstances.put(key, field.get(obj)); 88 mInstanceKeys.add(key); 89 } 90 field.set(obj, newValue); 91 } 92 93 private synchronized void restoreInstances() throws Exception { 94 Iterator<InstanceKey> it = mInstanceKeys.descendingIterator(); 95 96 while (it.hasNext()) { 97 InstanceKey key = it.next(); 98 Field field = key.mClass.getDeclaredField(key.mInstName); 99 field.setAccessible(true); 100 field.set(key.mObj, mOldInstances.get(key)); 101 } 102 103 mInstanceKeys.clear(); 104 mOldInstances.clear(); 105 } 106} 107