Home | History | Annotate | Download | only in cellbroadcastreceiver
      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 
     17 package com.android.cellbroadcastreceiver;
     18 
     19 import android.os.IBinder;
     20 import android.os.ServiceManager;
     21 import android.util.Log;
     22 
     23 import java.lang.reflect.Field;
     24 import java.util.HashMap;
     25 import java.util.Iterator;
     26 import java.util.LinkedList;
     27 
     28 // This class is for replacing existing system service with the mocked service.
     29 public 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