1. 程式人生 > >開源專案之Android imifirewall(防火牆)

開源專案之Android imifirewall(防火牆)

imifirewall(艾米防火牆)是一款Android下的防火牆軟體,它主要用來幫助手機使用者解決日常使用中遇到的問題:電話騷擾,釣魚簡訊,手機垃圾,系統變慢等眾多問題,艾米防火牆暫時只支援簡訊過濾,來電攔截,程式聯網行為攔截和流量檢視等功能,以後會陸續新增更多實用的功能。

不錯的國產防火牆專案,專案如圖:


效果如圖:


主要原始碼分析:

public class Function { // jni載入以及本地呼叫

	public static FileDescriptor createSubprocess(String cmd, String arg0,
			String arg1) {

		return createSubprocess(cmd, arg0, arg1, null);
	}

	public static native FileDescriptor createSubprocess(String cmd,
			String arg0, String arg1, int[] processId); // 建立子程序

	public static native void setPtyWindowSize(FileDescriptor fd, int row,
			int col, int xpixel, int ypixel); // 設定視窗大小

	public static native int waitFor(int processId); // 等待某程序

	public static native String version(); // 版本資訊

	static {
		System.loadLibrary("imiFunction");
	}
}

Jni專案就兩個檔案,如圖:


關鍵Api

public final class imiApi { // 封裝好的API 關鍵操作類

主要方法如下:

	private static boolean applyIptablesRulesImpl(Context ctx,
			List<Integer> uidsWifi, List<Integer> uids3g, boolean showErrors) { // 清除並重新新增所有規則(內部實現)
	public static boolean applySavedIptablesRules(Context ctx,
			boolean showErrors) {// 清除並重新新增所有已儲存的規則(而不是在記憶體中的)
	public static boolean applyIptablesRules(Context ctx, boolean showErrors) {// 清除並重新新增的所有規則
	public static void saveRules(Context ctx) {// 儲存當前使用規則
	public static boolean purgeIptables(Context ctx, boolean showErrors) {// 清除所有ip
	public static void showIptablesRules(Context ctx) { // 顯示ip
	public static DroidApp[] getApps(Context ctx) { // 獲得app資訊
	public static boolean hasRootAccess(Context ctx, boolean showErrors) { // 確認系統許可權
	public static int runScriptAsRoot(Context ctx, String script,
			StringBuilder res, final long timeout) { // 系統許可權執行一個指令碼
	public static int runScriptAsRoot(Context ctx, String script,
			StringBuilder res) throws IOException { // 執行一個指令碼根 設定一個預設的超時時間為20秒。
	public static String RunCustomCmd(String[] cmd, String workdirectory)	//執行自定義命令
	public static boolean isEnabled(Context ctx) { // 確認防火牆是否開啟
	public static void setEnabled(Context ctx, boolean enabled) { // 設定防火牆開啟與禁止
public class imiCallEngine extends PhoneStateListener { // 電話引擎 監聽手機狀態
主要方法如下:
	// 監聽電話線路
	public void StartListen(TelephonyManager telMgr) {
		telMgr.listen(this, LISTEN_CALL_STATE);
	}
public void Hangup() {	//結束通話電話
		// endCallExtend.endcall();

		ITelephony iTelephony = null;

		TelephonyManager tManager = (TelephonyManager) mContext
				.getSystemService(Context.TELEPHONY_SERVICE);

		// 初始化iTelephony
		Class<TelephonyManager> c = TelephonyManager.class;
		Method getITelephonyMethod = null;
		try {
			getITelephonyMethod = c.getDeclaredMethod("getITelephony",
					(Class[]) null);
			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) getITelephonyMethod.invoke(tManager,
					(Object[]) null);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		try {
			iTelephony.endCall();
		} catch (Exception e) {

		}

	}
其它關鍵方法:
	public void InstallShortCut() {	//初始化快接方法

		Intent shortcutIntent = new Intent(ACTION_INSTALL_SHORTCUT);

		shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
				getString(R.string.app_name)); // 快捷方式ICON
		shortcutIntent.putExtra(EXTRA_SHORTCUT_DUPLICATE, false); // 覆蓋以前的ICON

		Intent intent = new Intent();
		intent.setComponent(new ComponentName(this.getPackageName(),
				".ActivityMain")); // 設定快捷方式的啟動程式

		shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
		shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
				Intent.ShortcutIconResource.fromContext(this, R.drawable.icon));
		sendBroadcast(shortcutIntent);

	}
			public void onClick(View v) {	//執行shell命令
				// TODO Auto-generated method stub
				String et_input_value = actinput.getText().toString();
				String cmdoutput = "";
				ArrayList my_cmd_list = new ArrayList();
				if (et_input_value != null) {
					String mycmd = "'" + et_input_value.trim() + "'";

					my_cmd_list.add(0, "/system/bin/sh"); // shell path
					my_cmd_list.add(1, "-c");
					my_cmd_list.add(2, mycmd);

					int size = my_cmd_list.size();
					String[] my_cmd = new String[size];
					for (int i = 0; i < size; i++)
						my_cmd[i] = (String) my_cmd_list.get(i);
					try {
						cmdoutput = imiApi.RunCustomCmd(my_cmd, "/");
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					tv_output = (TextView) findViewById(R.id.output);
					tv_output.setText(cmdoutput);
					actinput.setText("");
				} else {
					tv_output = (TextView) findViewById(R.id.output);
					tv_output.setText("The Content Input is not proper!");
				}
			}
	private void setCallProfile() {	//設定電話的防騷擾策略
		// TODO Auto-generated method stub
		int callProfile = db.getOptionsIntData(Commons.CALLSpamType);

		ListPreference callProfilelist = (ListPreference) findPreference("call_setting");
		callProfilelist.setValueIndex(callProfile);

		switch (callProfile) {
		case Commons.CALL_PROFILE_NORMAL: {
			callProfilelist.setSummary(R.string.call_profile_normal);
			break;
		}
		case Commons.CALL_PROFILE_REJECT_UNKNOW: {
			callProfilelist.setSummary(R.string.call_profile_reject_unknow);
			break;
		}
		case Commons.CALL_PROFILE_REJECT_BL: {
			callProfilelist.setSummary(R.string.call_profile_reject_blacklist);
			break;
		}
		case Commons.CALL_PROFILE_ONLY_WL_: {
			callProfilelist.setSummary(R.string.call_profile_only_whitelist);
			break;
		}
		case Commons.CALL_PROFILE_REJECT_ALL: {
			callProfilelist.setSummary(R.string.call_profile_reject_all);
			break;
		}
		default:
			break;
		}
	}
	
	private void saveCallProfile() {	//儲存電話的防騷擾策略
		ListPreference callProfilelist = (ListPreference) findPreference("call_setting");

		db.updateOptionsData(Commons.CALLSpamType,
				Integer.parseInt(callProfilelist.getValue()));
	}

	private void setCallBack() {	//設定電話被拒的返回鈴音
		int backTone = db.getOptionsIntData(Commons.CallBackTone);

		ListPreference callProfilelist = (ListPreference) findPreference("call_back");
		callProfilelist.setValueIndex(backTone);

		switch (backTone) {
		case Commons.CALL_BUSY: {
			callProfilelist.setSummary(R.string.back_tone_busy);
			break;
		}
		case Commons.CALL_POWER_OFF: {
			callProfilelist.setSummary(R.string.back_tone_poweroff);
			break;
		}
		case Commons.CALL_OUT_OF_SERVICE: {
			callProfilelist.setSummary(R.string.back_tone_outservice);
			break;
		}
		default:
			break;
		}
	}

	void saveBackTone() {	//儲存電話的返回鈴音的設定
		ListPreference callProfilelist = (ListPreference) findPreference("back_tone");

		db.updateOptionsData(Commons.CallBackTone,
				Integer.parseInt(callProfilelist.getValue()));
	}

	void setMessageProfile() {//設定簡訊的防騷擾策略
		int message_type = db.getOptionsIntData(Commons.MessageSpamType);
		// mDb.getOptionsData(mOptionsData);
		ListPreference callProfilelist = (ListPreference) findPreference("message_profile");
		callProfilelist.setValueIndex(message_type);

		switch (message_type) {
		case Commons.MESSAGE_PROFILE_REJECT_UNKNOW: {
			callProfilelist.setSummary(R.string.message_profile_reject_unknow);
			break;
		}
		case Commons.MESSAGE_PROFILE_RECEIVING_ALL: {
			callProfilelist.setSummary(R.string.message_profile_receving_all);
			break;
		}
		default:
			break;
		}
	}

	void saveMessageProfile() {//儲存簡訊的防騷擾策略
		ListPreference callProfilelist = (ListPreference) findPreference("message_profile");

		db.updateOptionsData(Commons.MessageSpamType,
				Integer.parseInt(callProfilelist.getValue()));
	}

	void setFilterMessage() {	//設定是否進行垃圾簡訊過濾
		int filterValue = db.getOptionsIntData(Commons.MessageSpamFilter);
		CheckBoxPreference preference = (CheckBoxPreference) findPreference("spam_filter");

		preference.setChecked(filterValue > 0 ? true : false);
	}

	void saveFilterMessage() {	//儲存垃圾簡訊過濾策略
		CheckBoxPreference callProfilelist = (CheckBoxPreference) findPreference("spam_filter");

		db.updateOptionsData(Commons.MessageSpamFilter,
				callProfilelist.isChecked() ? 1 : 0);
	}

	private void callForwarding(String forwardNum, boolean isSetCallForward) {	// 設定來電轉駁選項
		String encoded = Uri.encode("#");
		TelephonyManager telMagr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		if (telMagr.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
			Intent intent = null;
			if (isSetCallForward) {
				intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:**67*"
						+ Uri.encode(forwardNum) + encoded));
			} else {
				intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"
						+ encoded + Uri.encode("67") + encoded));
			}

			startActivity(intent);
		} else {

			Intent intent = null;
			if (isSetCallForward) {
				intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:*900"));
			} else {
				intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:*90"
						+ forwardNum + encoded));

			}

			startActivity(intent);
		}
	}
	private void launchProcess(int pos) // 開啟程序
	{
		String app = ((PROEntity) mList.getItemAtPosition(pos))
				.getProcessName();
		Intent launch_intent = getPackageManager().getLaunchIntentForPackage(
				app);
		if (launch_intent != null) {
			startActivity(launch_intent);
		}
	}

	private void closeProcess(int pos) // 結束程序
	{
		String app = ((PROEntity) mList.getItemAtPosition(pos))
				.getProcessName();
		ActivityManager am = this.mActivityMgr;
		imiProcess.killByLevel7(am, app);
		((ProcessAdapter) mList.getAdapter()).removeContent(pos);
	}

	private void showProcessDetail(int pos) // 顯示程序詳細資訊
	{
		String app = ((PROEntity) mList.getItemAtPosition(pos))
				.getProcessName();
		Intent detail = Commons.getPackageDetailIntent(app);
		startActivity(detail);
	}
public class BootBroadcast extends BroadcastReceiver { // 啟動廣播

	private imiSql myPhoneDbHelper;
	private ITelephony iTelephony;
	static final String BOOT_ACTION = "android.intent.action.BOOT_COMPLETED";
	static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";
	static final String CALL_ACTION = "android.intent.action.PHONE_STATE";
	static final String OUT_ACTION = "android.intent.action.NEW_OUTGOING_CALL";
	final private String TAG = "imiFirewall_Receiver";

	@Override
	public void onReceive(Context context, Intent intent) {
		final SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(context);

		if (intent.getAction().equals(BOOT_ACTION)) { // 開機自啟動程式

			Log.d(TAG, "system boot completed");

			if (prefs.getBoolean("Network", true) == true) // 防火牆開關
			{
				if (!imiApi.applySavedIptablesRules(context, false)) {
					// Error enabling firewall on boot
					Toast.makeText(context, R.string.toast_error_enabling,
							Toast.LENGTH_SHORT).show();
					imiApi.setEnabled(context, false);
				}
			}
			// 清空流量統計的資料
			// Intent intentclean =new Intent(context,BootService.class);
			// context.startService(intentclean);
			// Intent intentnet =new Intent(context,NetService.class);
			// context.startService(intentnet);
		}
	}// OnReceiver_END
}

攔截事件在服務中,專案提供了三個服務,如下:
public class BootService extends Service { // 啟動服務
public class FireService extends Service implements CallEventListener { // 防火牆服務
public class NetService extends Service { // 網路監管服務
主要方法如下:
	public void processIncomingSMS(String smsPhone, String smsMessage, long date) {	//處理來信訊息
		Log.i("imi_get_message", smsMessage);
		if (!processSMSData(0, smsPhone, smsMessage, date, 1)) {
			// 如果簡訊未被處理,則將其插入至系統收件箱
			// insertSMSToSys(smsPhone,smsMessage,date);
		}
	}

	/*
	 * 監聽撥出電話的處理操作
	 */

	public void processOutgoingCall(String outGoingNumber) {

	}

	/*
	 * 監聽呼入電話的處理操作
	 */
	public void processCall(String incomingNumber) {
		if (db.isNumberInUserList(incomingNumber, Commons.VIP_LIST)) {
			Log.i("imi", "VIP number");

			mVIPIncomingNumber = incomingNumber;
			mVIPNeedDeleteLog = true;
		} else {
			boolean bNeedHangup = false;

			// 判斷其它情景模式
			switch (db.getOptionsIntData(Commons.CALLSpamType)) {
			case Commons.CALL_PROFILE_REJECT_UNKNOW: {
				if (getNameFromContacts(incomingNumber).length() <= 0) {
					bNeedHangup = true;
				}
				break;
			}

			case Commons.CALL_PROFILE_REJECT_BL: {
				if (db.isNumberInUserList(incomingNumber, Commons.BLACK_LIST)) {
					bNeedHangup = true;
				}
				break;
			}

			case Commons.CALL_PROFILE_ONLY_WL_: {
				if (!db.isNumberInUserList(incomingNumber, Commons.WHITE_LIST)) {
					bNeedHangup = true;
				}
				break;
			}
			case Commons.CALL_PROFILE_REJECT_ALL: {
				bNeedHangup = true;
				break;
			}

			default:
				break;
			}
			if (bNeedHangup) {
				mCallEngine.Hangup();

				clearSystemNotification();

				insertRecordToDb(incomingNumber, Commons.LOG_SPAM_CALL,
						Commons.LOG_SPAM_REJECT_CALL);

				setNotifyType(Commons.NEW_REJECT_CALL_NOTIFY);

				//

			}
		}
	}
	public void clearSystemNotification() {	//清除系統通知

		ITelephony iTelephony = null;

		TelephonyManager tManager = (TelephonyManager) this
				.getSystemService(Context.TELEPHONY_SERVICE);

		// 初始化iTelephony
		Class<TelephonyManager> c = TelephonyManager.class;
		Method getITelephonyMethod = null;
		try {
			getITelephonyMethod = c.getDeclaredMethod("getITelephony",
					(Class[]) null);
			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) getITelephonyMethod.invoke(tManager,
					(Object[]) null);
		} 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();
		}

		try {
			iTelephony.cancelMissedCallsNotification();// 刪除未接來電通知

			StringBuilder where = new StringBuilder("type=");
			where.append(Calls.MISSED_TYPE);
			where.append(" AND new=1");
			ContentValues values = new ContentValues(1);
			values.put(Calls.NEW, "0");
			this.getContentResolver().update(Calls.CONTENT_URI, values,
					where.toString(), null);

		} catch (Exception e) {

		}

	}
	boolean processSMSData(int contactsIndex, String phone, String body,
			long date, int type) {	//處理簡訊

		if (phone.length() > 0) {
			// 確認其為發出的簡訊

			if (db.isNumberInUserList(
					phone.length() > 9 ? phone.substring(phone.length() - 9,
							phone.length()) : phone, Commons.VIP_LIST)) {
				Commons.PDATA tempData = new Commons.PDATA();
				tempData.mStringValue_1 = contactsIndex > 0 ? getNameFromContacts(contactsIndex)
						: "";
				tempData.mStringValue_2 = phone;
				tempData.mStringValue_3 = body;
				tempData.mIntValue_1 = Commons.LOG_VIP_MESSAGE;
				tempData.mIntValue_2 = (type == 1) ? Commons.LOG_VIP_INCOMING_MESSAGE
						: Commons.LOG_VIP_OUTGOING_MESSAGE;
				tempData.mIntValue_3 = 0;
				tempData.mIntValue_4 = db.getMessageThreadId(phone);
				tempData.mDate = date;

				db.AddData(imiSql.DATABASE_TABLE_USERLOG, tempData);

				if (type == 1) {
					setNotifyType(Commons.NEW_VIP_MESSAGE_NOTIFY);
				}

				return true;
			} else if (type == 1) {
				// 判斷其是否為騷擾簡訊
				if ((db.getOptionsIntData(Commons.MessageSpamType) == Commons.MESSAGE_PROFILE_REJECT_UNKNOW && (type == 1 && contactsIndex == 0))
						|| (db.getOptionsIntData(Commons.MessageSpamFilter) > 0 && mSpamCharacter
								.isSpamMessage(body))) {
					Commons.PDATA tempData = new Commons.PDATA();
					tempData.mStringValue_1 = contactsIndex > 0 ? getNameFromContacts(contactsIndex)
							: "";
					tempData.mStringValue_2 = phone;
					tempData.mStringValue_3 = body;
					tempData.mIntValue_1 = Commons.LOG_SPAM_MESSAGE;
					tempData.mIntValue_2 = Commons.LOG_SPAM_MESSAGE;
					tempData.mIntValue_3 = 0;
					tempData.mDate = date;

					db.AddData(imiSql.DATABASE_TABLE_USERLOG, tempData);

					if (type == 1) {
						setNotifyType(Commons.NEW_SPAM_MESSAGE_NOTIFY);
					}

					return true;
				}
			}
		}

		return false;
	}

整個專案58個檔案,原始碼簡單易懂,它可直接移植我們的應用程式中,我們也可以開發一款類似360安全衛士的app了!~

專案下載