利用JAVA反射機制訪問ITelephony隱藏接口

這兩天研究如何利用程序掛斷電話。發現在Android1.0的時候Phone中提供了提供了endCall方法,而1.5以後這個方法被設置爲私有了。

如此有了如下研究:

 /**
  * 利用JAVA反射機制調用ITelephony的endCall()結束通話。
  */
 private void endCall() {
  // 初始化iTelephony
  Class<TelephonyManager> c = TelephonyManager.class;
  Method getITelephonyMethod = null;
  try {
   // 獲取所有public/private/protected/默認
   // 方法的函數,如果只需要獲取public方法,則可以調用getMethod.
   getITelephonyMethod = c.getDeclaredMethod("getITelephony",
     (Class[]) null);
   // 將要執行的方法對象設置是否進行訪問檢查,也就是說對於public/private/protected/默認
   // 我們是否能夠訪問。值爲 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。值爲 false
   // 則指示反射的對象應該實施 Java 語言訪問檢查。
   getITelephonyMethod.setAccessible(true);
  } catch (SecurityException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  try {
   ITelephony iTelephony = (ITelephony) getITelephonyMethod.invoke(
     tManager, (Object[]) null);
   try {
    iTelephony.endCall();
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  } catch (IllegalArgumentException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 

 

 

/******************************************************************************************/

     以下摘自---百度空間---描述瞭如何利用反射進行私有方法的單元測試

/******************************************************************************************/

 

利用安全管理器

 

安全性管理器與反射機制相結合,也可以達到我們的目的。Java 運行時依靠一種安全性管理器來檢驗調用代碼對某一特定的訪問而言是否有足夠的權限。具體來說,安全性管理器是 java.lang.SecurityManager 類或擴展自該類的一個類,且它在運行時檢查某些應用程序操作的權限。換句話說,所有的對象訪問在執行自身邏輯之前都必須委派給安全管理器,當訪問受到安全性管理器的控制,應用程序就只能執行那些由相關安全策略特別准許的操作。因此安全管理器一旦啓動可以爲代碼提供足夠的保護。默認情況下,安全性管理器是沒有被設置的,除非代碼明確地安裝一個默認的或定製的安全管理器,否則運行時的訪問控制檢查並不起作用。我們可以通過這一點在運行時避開 Java 的訪問控制檢查,達到我們訪問非公有成員變量或方法的目的。爲能訪問我們需要的非公有成員,我們還需要使用 Java 反射技術。Java 反射是一種強大的工具,它使我們可以在運行時裝配代碼,而無需在對象之間進行源代碼鏈接,從而使代碼更具靈活性。在編譯時,Java 編譯程序保證了私有成員的私有特性,從而一個類的私有方法和私有成員變量不能被其他類靜態引用。然而,通過 Java 反射機制使得我們可以在運行時查詢以及訪問變量和方法。由於反射是動態的,因此編譯時的檢查就不再起作用了。

下面的代碼演示瞭如何利用安全性管理器與反射機制訪問私有變量。


清單 3. 利用反射機制訪問類的成員變量

//獲得指定變量的值
public static Object getValue(Object instance, String fieldName) 
    
throws   IllegalAccessException, NoSuchFieldException {

     Field field 
= getField(instance.getClass(), fieldName);
    
// 參數值爲true,禁用訪問控制檢查
     field.setAccessible(true);
    
return field.get(instance);
}
 

//該方法實現根據變量名獲得該變量的值
public static Field getField(Class thisClass, String fieldName) 
    
throws NoSuchFieldException {

    
if (thisClass == null{
        
throw new NoSuchFieldException("Error field !");
     }

}

 

其中 getField(instance.getClass(), fieldName) 通過反射機制獲得對象屬性,如果存在安全管理器,方法首先使用 this 和 Member.DECLARED 作爲參數調用安全管理器的 checkMemberAccess 方法,這裏的 this 是 this 類或者成員被確定的父類。 如果該類在包中,那麼方法還使用包名作爲參數調用安全管理器的 checkPackageAccess 方法。 每一次調用都可能導致 SecurityException。當訪問被拒絕時,這兩種調用方式都會產生 securityexception 異常 。

setAccessible(true) 方法通過指定參數值爲 true 來禁用訪問控制檢查,從而使得該變量可以被其他類調用。我們可以在我們所寫的類中,擴展一個普通的基本類 java.lang.reflect.AccessibleObject 類。這個類定義了一種 setAccessible 方法,使我們能夠啓動或關閉對這些類中其中一個類的實例的接入檢測。這種方法的問題在於如果使用了安全性管理器,它將檢測正在關閉接入檢測的代碼是否允許這樣做。如果未經允許,安全性管理器拋出一個例外。

除訪問私有變量,我們也可以通過這個方法訪問私有方法。


清單 4. 利用反射機制訪問類的成員方法

public static Method getMethod(Object instance, String methodName, Class[] classTypes) 
    
throws   NoSuchMethodException {

     Method accessMethod 
= getMethod(instance.getClass(), methodName, classTypes);
    
//參數值爲true,禁用訪問控制檢查
     accessMethod.setAccessible(true);

    
return accessMethod;
}


private static Method getMethod(Class thisClass, String methodName, Class[] classTypes) 
    
throws NoSuchMethodException {

    
if (thisClass == null{
        
throw new NoSuchMethodException("Error method !");
     }
 try {
        
return thisClass.getDeclaredMethod(methodName, classTypes);
     }
 catch (NoSuchMethodException e) {
        
return getMethod(thisClass.getSuperclass(), methodName, classTypes);
            
     }

}

 

獲得私有方法的原理與獲得私有變量的方法相同。當我們得到了函數後,需要對它進行調用,這時我們需要通過 invoke() 方法來執行對該函數的調用,代碼示例如下:

 

//調用含單個參數的方法
public static Object invokeMethod(Object instance, String methodName, Object arg) 
    
throws NoSuchMethodException,
     IllegalAccessException, InvocationTargetException 
{

     Object[] args 
= new Object[1];
     args[
0= arg;
    
return invokeMethod(instance, methodName, args);
}

 
//調用含多個參數的方法
public static Object invokeMethod(Object instance, String methodName, Object[] args) 
    
throws NoSuchMethodException,
     IllegalAccessException, InvocationTargetException 
{
     Class[] classTypes 
= null;
    
if (args != null{
         classTypes 
= new Class[args.length];
        
for (int i = 0; i < args.length; i++{
            
if (args[i] != null{
                 classTypes[i] 
= args[i].getClass();
             }

         }

     }

    
return getMethod(instance, methodName, classTypes).invoke(instance, args);
}

 所需要的權限 <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />

 

利用安全管理器及反射,可以在不修改源碼的基礎上訪問私有成員,爲測試帶來了極大的方便。尤其是在編譯期間,該方法可以順利地通過編譯。但同時該方法也有一些缺點。第一個是性能問題,用於字段和方法接入時反射要遠慢於直接代碼。第二個是權限問題,有些涉及 Java 安全的程序代碼並沒有修改安全管理器的權限,此時本方法失效。

轉自http://blog.csdn.net/yangtaoJ2me/article/details/5752491

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章