当前位置:   article > 正文

Android 后台服务启动Actvity_android 后台启动服务

android 后台启动服务

一、问题背景

相机自动化测试需求,测试apk通过bindService绑定相机apk里面的一个服务,通过AIDL接口的方式向相机apk发送命令,服务接收到命令之后会拉起相机的Activity。原本没有人为干预的情况下是可以拉起这个Activity的,但是拉起Activity之前,我们如果按下Home键,让测试apk退出的话,后台服务就无法拉起Activity了。经过调查发现Android10 之后做了这个限制

https://developer.android.google.cn/guide/components/activities/background-starts

 二、项目需求框架

ITestApp通过bindService连接到ITestAppService,是跨进程的。

 ITestAppService是我们的相机应用里面的一个服务,主要是响应外部应用的命令;接收到外部应用的命令之后调用相机内部代码。

其中第一条命令一般就是启动 CameraActivity,就是后台服务启动Activity。

三、分析无法启动原因

当按了Home键之后,后台服务就无法启动相机Activity了,以下是ActivityTaskManager的日志,启动被终止了。

  1. 11-16 13:54:01.143 1160 8007 W ActivityTaskManager: Background activity start
  2. [callingPackage: com.android.camera2; callingUid: 10150; appSwitchState: 1;
  3. isCallingUidForeground: false; callingUidHasAnyVisibleWindow: false;
  4. callingUidProcState: FOREGROUND_SERVICE; isCallingUidPersistentSystemProcess: false;
  5. realCallingUid: 10150; isRealCallingUidForeground: false; realCallingUidHasAnyVisibleWindow: false;
  6. realCallingUidProcState: FOREGROUND_SERVICE; isRealCallingUidPersistentSystemProcess: false;
  7. originatingPendingIntent: null; allowBackgroundActivityStart: false;
  8. intent: Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=com.android.camera2/com.android.camera.CameraActivity (has extras) };
  9. callerApp: ProcessRecord{a469c90 22598:com.android.camera2/u0a150}; inVisibleTask: false]

反正就是一堆启动的条件都没有满足,所以终止了。

拦截的逻辑就在系统ActivityStarter.java的这个方法里面,反正就是一个条件都不满足了。

四、相机应用解决办法、

AMS WMS的相关代码太复杂,没有过多时间仔细研究。简单看了一下shouldAbortBackgroundActivityStart里面返回false的逻辑,有些还是很好理解的。

像这一段表明只要在相机应用的AndroidManifest.xml文件里面加上android:sharedUserId=“android.uid.system“ 这一行就可以了,实际验证之后发现确实可行。

 

 像这一段 说明只要应用有SYSTEM_ALERT_WINDOW 权限就可以了,实测也是可以的

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

 五、测试应用解决办法

如果不想在被测应用加权限/设置android:sharedUserId,也可以在测试端想办法,我们的做法是在测试应用里面加一个浮窗,那么应用退出的时候浮窗还在,还能继续启动被测应用的activity。

浮窗代码也是copy的,就是通过一个服务启动的

  1. public class FloatingService extends Service {
  2. private static final String TAG = "CAMTEST_FloatingService";
  3. public FloatingService() {
  4. }
  5. @Override
  6. public void onCreate() {
  7. super.onCreate();
  8. Log.d(TAG, "onCreate");
  9. }
  10. @Override
  11. public void onDestroy() {
  12. super.onDestroy();
  13. Log.d(TAG, "onDestroy");
  14. }
  15. @Nullable
  16. @Override
  17. public IBinder onBind(Intent intent) {
  18. return null;
  19. }
  20. @Override
  21. public int onStartCommand(Intent intent, int flags, int startId) {
  22. showFloatingWindow();
  23. return super.onStartCommand(intent, flags, startId);
  24. }
  25. WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
  26. private void showFloatingWindow() {
  27. if (Settings.canDrawOverlays(this)) {
  28. // 获取WindowManager服务
  29. WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
  30. // 新建悬浮窗控件
  31. TextView textView = new TextView(getApplicationContext());
  32. textView.setText("接口测试需要, 勿惊...");
  33. textView.setTextColor(0xffff0000);
  34. textView.setGravity(Gravity.CENTER);
  35. textView.setBackgroundColor(Color.parseColor("#FF6200EE"));
  36. textView.setOnTouchListener(new FloatingOnTouchListener());
  37. // 设置LayoutParam
  38. int screenWidth = windowManager.getDefaultDisplay().getWidth();
  39. int screenHeight = windowManager.getDefaultDisplay().getHeight();
  40. layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
  41. layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
  42. layoutParams.format = PixelFormat.RGBA_8888;
  43. layoutParams.width = 500;
  44. layoutParams.height = 100;
  45. layoutParams.x = screenWidth - layoutParams.width;
  46. layoutParams.y = screenHeight - layoutParams.height;
  47. // 将悬浮窗控件添加到WindowManager
  48. windowManager.addView(textView, layoutParams);
  49. }
  50. }
  51. private class FloatingOnTouchListener implements View.OnTouchListener {
  52. private int x;
  53. private int y;
  54. @Override
  55. public boolean onTouch(View view, MotionEvent event) {
  56. switch (event.getAction()) {
  57. case MotionEvent.ACTION_DOWN:
  58. x = (int) event.getRawX();
  59. y = (int) event.getRawY();
  60. break;
  61. case MotionEvent.ACTION_MOVE:
  62. int nowX = (int) event.getRawX();
  63. int nowY = (int) event.getRawY();
  64. int movedX = nowX - x;
  65. int movedY = nowY - y;
  66. x = nowX;
  67. y = nowY;
  68. layoutParams.x = layoutParams.x + movedX;
  69. layoutParams.y = layoutParams.y + movedY;
  70. // 更新悬浮窗控件布局
  71. WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
  72. windowManager.updateViewLayout(view, layoutParams);
  73. break;
  74. default:
  75. break;
  76. }
  77. return false;
  78. }
  79. }
  80. }

启动地方代码

  1. public void startFloatingService(View view) {
  2. if (!Settings.canDrawOverlays(this)) {
  3. Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
  4. startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);
  5. } else {
  6. Log.d(TAG, "startFloatingService startService");
  7. startService(new Intent(MainActivity.this, FloatingService.class));
  8. }
  9. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/247545
推荐阅读
相关标签
  

闽ICP备14008679号