为了不让别人查看隐私,我们经常会对各种应用进行加锁。目前应用市场上应用锁有很多,各种安全类软件都有这个功能。
对于第三方软件,其实现应用锁的基本原理就是不断的轮询栈顶的应用包名,如果是在加锁名单里的应用,则会弹出解锁界面。这种方式的缺点比较明显,应用实际上已经启动起来了,只是强行在上面又盖了一层界面,同时也避免不了会先看到应用的界面然后才弹出解锁界面的问题。具体实现可查看http://blog.csdn.net/turkeycock/article/details/50521103
如果有root权限,就可以避免该这些问题。下面看下具有系统权限的app的应用锁实现方案。
应用锁从用户的角度看是对应用进行加锁,但是从系统的角度看,其实是对activity的拦截。
其实现原理比较简单,在startActivity的过程中,我们注意到
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
...
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
resultRecord, resultStack, options);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data
// stripped off, since it can contain private information.
Intent watchIntent = intent.cloneFilter();
abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
mService.mController = null;
}
}
...
if (abort) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
RESULT_CANCELED, null);
}
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
ActivityOptions.abort(options);
return START_SUCCESS;
}
...
}
这里有个abort变量,如果其为true,那么就直接返回了,不会再去继续startActivity的流程。
看下赋值的地方
abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
mController是IActivityController类型的对象,通过IActivityController实现对activity的拦截。
因此只要mController的activityStarting返回false,abor就会t设置为true,activity将不会启动,这时我们可以启动加锁页面,如果用户输入了正确的密码,再去把要启动的activity启动起来,达到应用锁的目的。
frameworks/base/core/java/android/app/IActivityController.java
/**
* Testing interface to monitor what is happening in the activity manager
* while tests are running. Not for normal application development.
* {@hide}
*/
interface IActivityController
{
/**
* The system is trying to start an activity. Return true to allow
* it to be started as normal, or false to cancel/reject this activity.
*/
boolean activityStarting(in Intent intent, String pkg);
/**
* The system is trying to return to an activity. Return true to allow
* it to be resumed as normal, or false to cancel/reject this activity.
*/
boolean activityResuming(String pkg);
/**
* An application process has crashed (in Java). Return true for the
* normal error recovery (app crash dialog) to occur, false to kill
* it immediately.
*/
boolean appCrashed(String processName, int pid,
String shortMsg, String longMsg,
long timeMillis, String stackTrace);
/**
* Early call as soon as an ANR is detected.
*/
int appEarlyNotResponding(String processName, int pid, String annotation);
/**
* An application process is not responding. Return 0 to show the "app
* not responding" dialog, 1 to continue waiting, or -1 to kill it
* immediately.
*/
int appNotResponding(String processName, int pid, String processStats);
/**
* The system process watchdog has detected that the system seems to be
* hung. Return 1 to continue waiting, or -1 to let it continue with its
* normal kill.
*/
int systemNotResponding(String msg);
}
boolean activityStarting(in Intent intent, String pkg);
pkg是要启动的activity的包名,在这个方法里我们可以去判断这个pkg是否需要加锁,如果需要则返回false拦截该activity的启动,如果不需要加锁则返回true继续startActivity的过程。
ams中也提供了设置该监听器的方法
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void setActivityController(IActivityController controller, boolean imAMonkey) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"setActivityController()");
synchronized (this) {
mController = controller;
mControllerIsAMonkey = imAMonkey;
Watchdog.getInstance().setActivityController(controller);
}
}
通过IActivityController可以实现真正的应用锁。