android安全問題(二) 程序鎖

導讀:本文介紹如何實現對應用加鎖的功能,無須root權限

 

某些人有時候會有這樣一種需求,小A下載了個軟件,只是軟件中的美女過於誘惑與暴露,所以他不想讓別人知道這是個什麼軟件,起碼不想讓別人打開瀏覽。而這款軟件又沒有鎖,任何人都可以打開,腫麼辦呢?如果打開它的時候需要輸入密碼,那該多好阿!於是,程序鎖這種應用就產生了

 

程序鎖不是最近纔有的,很久之前android就有這種apk了

這一期我們來苛刻如何實現程序加鎖功能

 

首先,我們先明確一下我們要做的程序具有什麼功能

1可以選擇需要加鎖的程序

2可以設置密碼

3可以關閉程序鎖

 

這裏作爲演示,我們就儘量簡化代碼

我們先說最關鍵的部分

最關鍵的地方在於:當用戶打開一個應用的時候,怎麼彈出密碼頁面?

這裏沒有什麼太好的辦法,需要掃描task中的topActivity

首先,我們先獲得運行的task

Java代碼 複製代碼 收藏代碼
  1. mActivityManager = (ActivityManager) context.getSystemService("activity");   
  2. //mActivityManager.getRunningTasks(1);//List<RunningTaskInfo>  
mActivityManager = (ActivityManager) context.getSystemService("activity");
//mActivityManager.getRunningTasks(1);//List<RunningTaskInfo>

getRunningTasks方法返回一個List,我們來看看這個List是什麼

getRunningTasks 寫道
Return a list of the tasks that are currently running, with the most recent being first and older ones after in order.
…… 

返回的List是有序的,第一個是最近的,所以我們取出第一個即可,然後得到此task中的最上層的Activity

Java代碼 複製代碼 收藏代碼
  1. ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;  
ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;

topActivity居然是ComponentName類型,下面的事情就好辦了,獲得包名和類名

Java代碼 複製代碼 收藏代碼
  1. ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;   
  2. String packageName = topActivity.getPackageName();   
  3. String className = topActivity.getClassName();   
  4. Log.v(TAG, "packageName" + packageName);   
  5. Log.v(TAG, "className" + className);   
  6.   
  7. if (testPackageName.equals(packageName)   
  8.         && testClassName.equals(className)) {   
  9.     Intent intent = new Intent();   
  10.     intent.setClassName("com.example.locktest""com.example.locktest.PasswordActivity");   
  11.     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   
  12.     mContext.startActivity(intent);   
  13. }  
ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;
String packageName = topActivity.getPackageName();
String className = topActivity.getClassName();
Log.v(TAG, "packageName" + packageName);
Log.v(TAG, "className" + className);

if (testPackageName.equals(packageName)
		&& testClassName.equals(className)) {
	Intent intent = new Intent();
	intent.setClassName("com.example.locktest", "com.example.locktest.PasswordActivity");
	intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	mContext.startActivity(intent);
}

 

由於我沒有選擇程序這一步,所以我就固定一個應用做測試,這裏選擇的是htc的note應用

Java代碼 複製代碼 收藏代碼
  1. String testPackageName = "com.htc.notes";   
  2. String testClassName = "com.htc.notes.collection.NotesGridViewActivity";  
String testPackageName = "com.htc.notes";
String testClassName = "com.htc.notes.collection.NotesGridViewActivity";

 

下面我們該想,這段代碼何時執行了

打開一個應用程序,系統不會發送廣播,我們無法直接監聽,所以這裏我們採取定時掃描的策略

這裏只是一個簡單的實現,之後我們再討論優化

我們採取每秒中檢查一次task的方式,這裏使用Timer吧,用Handler也一樣可以實現

Java代碼 複製代碼 收藏代碼
  1. private Timer mTimer;   
  2. private void startTimer() {   
  3.     if (mTimer == null) {   
  4.         mTimer = new Timer();   
  5.         LockTask lockTask = new LockTask(this);   
  6.         mTimer.schedule(lockTask, 0L, 1000L);   
  7.     }   
  8. }  
private Timer mTimer;
private void startTimer() {
	if (mTimer == null) {
		mTimer = new Timer();
		LockTask lockTask = new LockTask(this);
		mTimer.schedule(lockTask, 0L, 1000L);
	}
}

到這裏,其實我們的關鍵代碼就已經完成了

 

 

下面貼出完整帶代碼,注意:我們只關注彈出鎖界面這部分,其他部分自行實現(比如文章末尾提到的)

Task,負責檢查task,並在適當的時候彈出密碼頁面

 

Java代碼 複製代碼 收藏代碼
  1. public class LockTask extends TimerTask {   
  2.     public static final String TAG = "LockTask";   
  3.     private Context mContext;   
  4.     String testPackageName = "com.htc.notes";   
  5.     String testClassName = "com.htc.notes.collection.NotesGridViewActivity";   
  6.   
  7.     private ActivityManager mActivityManager;   
  8.   
  9.     public LockTask(Context context) {   
  10.         mContext = context;   
  11.         mActivityManager = (ActivityManager) context.getSystemService("activity");   
  12.     }   
  13.   
  14.     @Override  
  15.     public void run() {   
  16.         ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;   
  17.         String packageName = topActivity.getPackageName();   
  18.         String className = topActivity.getClassName();   
  19.         Log.v(TAG, "packageName" + packageName);   
  20.         Log.v(TAG, "className" + className);   
  21.   
  22.         if (testPackageName.equals(packageName)   
  23.                 && testClassName.equals(className)) {   
  24.             Intent intent = new Intent();   
  25.             intent.setClassName("com.example.locktest""com.example.locktest.PasswordActivity");   
  26.             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   
  27.             mContext.startActivity(intent);   
  28.         }   
  29.     }   
  30. }  
public class LockTask extends TimerTask {
	public static final String TAG = "LockTask";
	private Context mContext;
	String testPackageName = "com.htc.notes";
	String testClassName = "com.htc.notes.collection.NotesGridViewActivity";

	private ActivityManager mActivityManager;

	public LockTask(Context context) {
		mContext = context;
		mActivityManager = (ActivityManager) context.getSystemService("activity");
	}

	@Override
	public void run() {
		ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;
		String packageName = topActivity.getPackageName();
		String className = topActivity.getClassName();
		Log.v(TAG, "packageName" + packageName);
		Log.v(TAG, "className" + className);

		if (testPackageName.equals(packageName)
				&& testClassName.equals(className)) {
			Intent intent = new Intent();
			intent.setClassName("com.example.locktest", "com.example.locktest.PasswordActivity");
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			mContext.startActivity(intent);
		}
	}
}

 

LockService,負責執行定時任務,取消任務等

Java代碼 複製代碼 收藏代碼
  1. public class LockService extends Service {   
  2.     private Timer mTimer;   
  3.     public static final int FOREGROUND_ID = 0;   
  4.   
  5.     private void startTimer() {   
  6.         if (mTimer == null) {   
  7.             mTimer = new Timer();   
  8.             LockTask lockTask = new LockTask(this);   
  9.             mTimer.schedule(lockTask, 0L, 1000L);   
  10.         }   
  11.     }   
  12.   
  13.     public IBinder onBind(Intent intent) {   
  14.         return null;   
  15.     }   
  16.   
  17.     public void onCreate() {   
  18.         super.onCreate();   
  19.         startForeground(FOREGROUND_ID, new Notification());   
  20.     }   
  21.   
  22.     public int onStartCommand(Intent intent, int flags, int startId) {   
  23.         startTimer();   
  24.         return super.onStartCommand(intent, flags, startId);   
  25.     }   
  26.   
  27.     public void onDestroy() {   
  28.         stopForeground(true);   
  29.         mTimer.cancel();   
  30.         mTimer.purge();   
  31.         mTimer = null;   
  32.         super.onDestroy();   
  33.     }   
  34. }  
public class LockService extends Service {
	private Timer mTimer;
	public static final int FOREGROUND_ID = 0;

	private void startTimer() {
		if (mTimer == null) {
			mTimer = new Timer();
			LockTask lockTask = new LockTask(this);
			mTimer.schedule(lockTask, 0L, 1000L);
		}
	}

	public IBinder onBind(Intent intent) {
		return null;
	}

	public void onCreate() {
		super.onCreate();
		startForeground(FOREGROUND_ID, new Notification());
	}

	public int onStartCommand(Intent intent, int flags, int startId) {
		startTimer();
		return super.onStartCommand(intent, flags, startId);
	}

	public void onDestroy() {
		stopForeground(true);
		mTimer.cancel();
		mTimer.purge();
		mTimer = null;
		super.onDestroy();
	}
}

 

MainActivity,測試用,作爲應用入口,啓動service(產品中,我們可以在receiver中啓動service)。

Java代碼 複製代碼 收藏代碼
  1. public class MainActivity extends Activity {   
  2.   
  3.     public void onCreate(Bundle savedInstanceState){   
  4.         super.onCreate(savedInstanceState);   
  5.         startService(new Intent(this, LockService.class));   
  6.     }   
  7. }  
public class MainActivity extends Activity {

	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		startService(new Intent(this, LockService.class));
	}
}

 

PasswordActivity,密碼頁面,很粗糙,沒有核對密碼邏輯,自行實現

記得重寫onBackPressed函數,不然按返回鍵的時候……你懂的

Java代碼 複製代碼 收藏代碼
  1. public class PasswordActivity extends Activity {   
  2.   
  3.     private static final String TAG = "PasswordActivity";   
  4.     Button okButton;   
  5.     EditText passwordEditText;   
  6.     private boolean mFinish = false;   
  7.        
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {   
  10.         super.onCreate(savedInstanceState);   
  11.         setContentView(R.layout.password);   
  12.         passwordEditText = (EditText) findViewById(R.id.password);   
  13.          okButton = (Button) findViewById(R.id.ok);   
  14.          okButton.setOnClickListener(new View.OnClickListener() {   
  15.             public void onClick(View v) {   
  16.                 String password = passwordEditText.getText().toString();   
  17.                 Log.v(TAG, "password" + password);   
  18.                 mFinish = true;   
  19.                 finish();   
  20.             }   
  21.         });   
  22.     }   
  23.   
  24.     public void onBackPressed(){}   
  25.        
  26.     public void onPause(){   
  27.         super.onPause();   
  28.         if(!mFinish){   
  29.             finish();   
  30.         }   
  31.     }   
  32. }  
public class PasswordActivity extends Activity {

	private static final String TAG = "PasswordActivity";
	Button okButton;
	EditText passwordEditText;
	private boolean mFinish = false;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.password);
		passwordEditText = (EditText) findViewById(R.id.password);
		 okButton = (Button) findViewById(R.id.ok);
		 okButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				String password = passwordEditText.getText().toString();
				Log.v(TAG, "password" + password);
				mFinish = true;
				finish();
			}
		});
	}

	public void onBackPressed(){}
	
	public void onPause(){
		super.onPause();
		if(!mFinish){
			finish();
		}
	}
}

 

xml這裏就不貼了,記得添加權限

Xml代碼 複製代碼 收藏代碼
  1. <uses-permission android:name="android.permission.GET_TASKS"/>  

 

 

 

關於程序的其他部分,這裏只做簡要說明

選擇應用對其進行加鎖部分

1列出系統中所有程序(你也可以自由發揮,比如過濾掉原始應用)

2選擇,然後存入數據庫(當然,最好也有取消功能,記得從數據庫中刪除數據)

程序鎖總開關

可以使用sharedPreference,設置一個boolean開關

 

 

現在,當我想要打開htc的note應用的時候,就會彈出密碼頁面當我解鎖,按home會回到桌面,長按home,點擊note,還是會彈出密碼框

因爲是每秒檢查一次,所以可能會有一點點延遲,你可以設置爲500毫秒,但是越頻繁,佔用資源就越多

 

上面的代碼我取得topActivity後檢查了其包名行和類名,所以只有當打開指定的頁面的時候,纔會彈出密碼鎖

比如我對Gallery應用加密了,但是用戶正在編輯短信,這時候它想發彩信,於是他通過短信進入到了Gallery……

對於某些用戶的某些需求來說,這是不能容忍的,這時,我們只需簡單修改下判斷邏輯即可:只檢查包名,包名一致就彈出密碼鎖,這樣就完美了

 

程序鎖我就分析到這裏

最後一句

當使用程序鎖的時候,你長按home,發現程序鎖也出現在“最近的任務”中,腫麼辦……給此activity設置android:excludeFromRecents="true"即可



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