在android5.0以后,引入了多用户的概念,当我们在第三方服务中调用启动系统相关的服务(如:KeyguardService)时,如果仍然用bindService方式进行启动,
在系统进行用户切换或者切换访客模式等操作时会导致重复启动系统服务 KeyguardService,从而使得系统崩溃报错。
故需要利用bindServiceAsUser方式进行替换来实现绑定服务的调用方式。
在 frameworks\base\policy\src\com\android\internal\policy\impl\keyguard\KeyguardServiceDelegate.java 类中有绑定KeyguardService的代码,
其也是利用bindServiceAsUser方式来实现获取KeyguardService的实例。
tips:在Service中启动activity时也需要用startActivityAsUser(intent,UserHandle.CURRENT_OR_SELF);的方式进行activity的启动,否则无法成功启动相关activity。
代码如下:
import com.android.internal.policy.IKeyguardService;
import android.app.IProcessObserver;
import android.app.ActivityManagerNative;
private KeyguardManager.KeyguardLock mLock;
private KeyguardManager mKeyguardManager;
private TelephonyManager mTelemanager;
private PowerManager.WakeLock mWakeLock;
private PowerManager mPowerManager;
private IKeyguardService mKeyguardService;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "FpService $$$$ 444 $$$$ onCreate BOOT_COMPLETED = "
+ BOOT_COMPLETED);
mContext = this;
mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
mLock = mKeyguardManager.newKeyguardLock("KeyguardLock");
mTelemanager = (TelephonyManager) getSystemService(Service.TELEPHONY_SERVICE);
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
// bind to KeyguardService
bindService(this);
if(!FpControllerNative.S_SDK_ONLY){
try {
ActivityManagerNative.getDefault().registerProcessObserver(
new IProcessObserver.Stub() {
@Override
public void onForegroundActivitiesChanged(int pid,
int uid, boolean foregroundActivities) {
synchronized (lock) {
Log.d(DataUtil.TAG_LOG, TAG
+ " onForegroundActivitiesChanged pid = "
+ pid + " --uid: " + uid
+ " isForegroundAct: " + foregroundActivities);
if (foregroundActivities) {
PackageManager pm = getPackageManager();
mForegroundPkgs = pm.getPackagesForUid(uid);
mCurrentPid = pid;
mHandler.removeCallbacks(mShowPwdRunnable);
// the delay time must need because of some APP
// has a activity jump, if not delay time may be can't
// locked the APP.(etc. MeiYanCamera)
mHandler.postDelayed(mShowPwdRunnable,
SHOW_PASSWORD_ACTIVITY_DELAY);
} else {
mHandler.removeCallbacks(mShowPwdDelayRunnable);
mHandler.postDelayed(mShowPwdDelayRunnable,
UNMATCH_DIALOG_NORMAL_TIMEOUT);
}
}
}
@Override
public void onProcessStateChanged(int pid, int uid,
int importance) {
Log.d(TAG, "onProcessStateChanged pid = " + pid
+ ":" + uid + ":" + importance);
}
@Override
public void onProcessDied(int pid, int uid) {
Log.d(TAG, "onProcessDied pid = " + pid + ":" + uid);
}
});
} catch (RemoteException e) {
Log.d(TAG, " FpService RemoteException occurs, " + e);
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "FpService onDestroy");
mLock.reenableKeyguard();
unbindService(mKeyguardConnection);
}
public void bindService(Context context) {
Intent intent = new Intent();
intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
// use the 'bindServiceAsUser' to replace the 'bindService' if the android version after 5.0
// because of support the multiple user in android.
//if (!context.bindService(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE)) {
if (!context.bindServiceAsUser(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE,
UserHandle.OWNER)) {
Log.v(DataUtil.TAG_LOG, TAG + " ** bindService: can't bind to "
+ KEYGUARD_CLASS);
} else {
Log.v(DataUtil.TAG_LOG, TAG + " ** bindService started");
}
}
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v(DataUtil.TAG_LOG, TAG + " ** Keyguard connected (yay!)");
mKeyguardService = IKeyguardService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v(DataUtil.TAG_LOG, TAG + " ** Keyguard disconnected (boo!)");
mKeyguardService = null;
}
};
public boolean unLock(boolean wakeupLock) {
Log.d(TAG, " unLock before keyguardDone");
try {
if(!wakeupLock){
mKeyguardService.keyguardDone(false, true);
}else{
mKeyguardService.fpKeyguardDone(false,true);
}
} catch (RemoteException e) {
Log.e(TAG, " unLock occurs RemoteException when keyguardDone" + e);
}
// mKeyguardManager.dismissKeyguard();
return true;
}