Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 高版本Android如何利用反射調用系統隱藏的遠程服務攔截來電

高版本Android如何利用反射調用系統隱藏的遠程服務攔截來電

編輯:關於Android編程

要說攔截Android系統來電,就不得不說起在低版本的時候Android提供給開發者使用的一個方法:endCall(),但由於谷歌後來考慮到對於一部手機來說,最重要的功能就是打電話了,如果這個功能隨隨便便就被人屏蔽了,安全性太差,所以在高版本的Android將這個方法屏蔽了,不再在TelephoneManager中暴露這個方法。


那麼我們下面的目標就是要想辦法調用到這個方法,當然首先我們還是需要實現一個廣播接收者,來接收電話狀態改變的廣播,這裡使用在服務中動態注冊廣播接收者的方法來實現,主要好處在於便於控制廣播接收者的生命周期,同時也能比靜態注冊有更高的權限

private static final String PHONE = "PHONE";
	private static final String BOTH = "BOTH";
	private static final String SMS = "SMS";
	private TelephonyManager tm;
	private BlacklistDao dao;
	private inCommingCallReceiver callReceiver;
	private PhoneStateListener listener;
@Override
	public IBinder onBind(Intent intent) {
		return null;
	}


	@Override
	public void onCreate() {
		super.onCreate();
		tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		dao = new BlacklistDao(this, 1);

		callReceiver = new inCommingCallReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction("android.intent.action.PHONE_STATE");
		filter.addAction("android.provider.Telephony.SMS_RECEIVED");
		filter.setPriority(Integer.MAX_VALUE);
		listener = new PhoneStateListener() {


			private BlacklistItem blacklistItem;


			@Override
			public void onCallStateChanged(int state, String incomingNumber) {
				super.onCallStateChanged(state, incomingNumber);
				switch (state) {
				case TelephonyManager.CALL_STATE_RINGING:// 如果是來電的時候
					blacklistItem = dao.queryItem(incomingNumber);


					if (blacklistItem != null) {
						String type = blacklistItem.getType();
						if ((BOTH.equals(type) || PHONE.equals(type))) {
							System.out.println("掛斷電話");
							hangUpCallFromBlacklist(incomingNumber);//掛斷電話的方法
						}
					}


					break;


				default:
					break;
				}


			}


		};
		registerReceiver(callReceiver, filter);// 注冊廣播接收者
	}

在服務的onDestroy()方法中取消注冊廣播接收者:


@Override
	public void onDestroy() {
		super.onDestroy();
		System.out.println("關閉黑名單服務");
		unregisterReceiver(callReceiver);
		// 取消監聽
		tm.listen(listener, PhoneStateListener.LISTEN_NONE);
		// listener = null;
	}


內部類廣播接收者,用於接收電話狀態改變的廣播:

/**
	 * 監聽來電
	 * 
	 * @author Alex
	 * 
	 */
	private class inCommingCallReceiver extends BroadcastReceiver {


		private BlacklistItem blacklistItem;


		@Override
		public void onReceive(Context context, Intent intent) {
			if ("android.intent.action.PHONE_STATE".equals(intent
					.getAction())) {
				// 如果收到的是電話狀態的變化
				tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
			}
		}
	}


下面我們重點來看hangUpCallFromBlacklist(incomingNumber);這個實現掛斷來電的方法,其中incomingNumber是來電的電話號碼。

按照我的慣例,還是從安卓系統的源碼入手,由於endCall方法原來是在TelephoneManager中的,所以我們不妨從TelephoneManager的實例化方法getSystemService入手:

\

\

我們可以發現這個方法是定義在ContextWrapper中的,而ContextWrapper又是繼承自Context,我們不妨進入到Context的源碼中去一探究竟:

\

在Context中,我們只找到了一個getSystemService的抽象方法,那麼如何去找實現方法呢,在java中,抽象類的實現類一般名字都是在抽象類名後面加上一個"Impl",於是我們去搜索源碼中的ContextImpl.java,找到之後打開發現:

\

我們發現getSystemService實際上返回了一個ServiceFetcher對象的一個getService方法的結果,我們來看看ServiceFetcher的getService方法:

\


在這裡我們可以看到,在定義了一個static塊中,注冊了很多不同的service服務,而這些gerService方法都是由ServiceManager來調用的,返回值是一個IBinder對象。接下來我們可以在文件的導入包的部分找到ServiceManager的位置是在android/os下的:

\

由於getService返回的是一個IBinder對象,我們只要找到這個getService方法的實現,就可以傳入TELEPONY_SERVICE從而拿到真正的TelephonyManager所代理的那個遠程服務綁定對象,從而調用隱藏在其中的endCall方法。
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+0NLUy7XEysejrNTaU2VydmljZU1uYWdlci5qYXZh1tCjrM7Sw8fV0rW9wctnZXRTZXJ2aWNlt723qLXEyrXP1jo8L3A+CjxwPjxpbWcgc3JjPQ=="/uploadfile/Collfiles/20140924/20140924090000134.png" alt="\">

\

我們可以發現,ServiceManager這個類也是一個隱藏類,我們無法在我們的代碼中直接拿到這個類來調用其中的getService方法來獲取IBinder對象,那麼我們要如何做呢?

這裡就只有使用反射的方法來處理:

Class clazz = CallSmsSafeService.class.getClassLoader().loadClass(
					"android.os.ServiceManager");
		Method method = clazz.getMethod("getService", String.class);
		IBinder binder = (IBinder) method.invoke(null, TELEPHONY_SERVICE);
通過上面的反射做法,我們拿到了對應於TelephonyManager的IBinder對象,下面我們需要做的利用aidl來調用遠程方法,既然是使用的TelephonyManager的IBinder對象,我們再進入到TelephonyManager的源碼中去看看:

\

我們發現,在TelephonyManager中,類似於getCallState()這類的方法基本都返回的是getITelephony()的返回值調用的方法,那麼這個getITelephy()是什麼呢:

\

我們發現,返回的實際上是一個ITelephony對象,而且是以一種調用遠程服務方法的形式返回的;

我們在文件的頭部找到ITelephony的位置:

\

打開上面的目錄,我們發現ITelephony是一個aidl文件,進入其中,我們可以找到endCall方法:

\

由於在ITelephony.aidl的頭部有如下信息:

\

我們想要通過aidl來調用遠程服務telephony的方法endCall(),我們需要將Telehpony.aidl拷貝到我們工程中新建的com.android.internal.telephony包中,同時將android.telephony.NeighboringCellInfo.aidl文件拷貝到工程中新建的android.telephony包中,這樣在gen目中下就會自動生成一個對應的ITelephony.java文件。至此,我們就可以使用下面的語句來調用遠程服務的endCall方法:

ITelephony.Stub.asInterface(binder).endCall();

最後,不要忘記在清單文件中加入對應的權限:


      
    
    



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved