這兩天研究如何利用程式掛斷電話。發現在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); }
利用安全管理器及反射,可以在不修改源碼的基礎上訪問私人成員,為測試帶來了極大的方便。尤其是在編譯期間,該方法可以順利地通過編譯。但同時該方法也有一些缺點。第一個是效能問題,用於欄位和方法接入時反射要遠慢於直接代碼。第二個是許可權問題,有些涉及 Java 安全的程式碼並沒有修改安全管理器的許可權,此時本方法失效。