your programing

Android가 포 그라운드 서비스를 종료합니다.

lovepro 2020. 10. 13. 08:20
반응형

Android가 포 그라운드 서비스를 종료합니다.


업데이트 : 문제에 대한 진정한 해결책을 찾지 못했습니다. 내가 생각 해낸 것은 연결이 끊어 질 때마다 이전 블루투스 장치에 자동으로 다시 연결하는 방법이었습니다. 이상적이지는 않지만 상당히 잘 작동하는 것 같습니다. 나는 이것에 관한 더 많은 제안을 듣고 싶습니다.

나는이 질문에서와 거의 같은 문제가 있습니다 : wake lock을 유지하는 동안 서비스가 종료되고 장치 (Asus Transformer)를 포함하여 startForeground호출 한 후 서비스가 중지되기까지의 시간 (30-45 분), 사용 wake lock, startForeground () 사용 및 화면이 꺼질 때 앱이 열려 있으면 문제가 발생하지 않는다는 사실.

내 앱은 다른 기기와 블루투스 연결을 유지하고 두 기기간에 데이터를 전송하므로 데이터를 수신하려면 항상 활성화되어 있어야합니다. 사용자는 마음대로 서비스를 시작하고 중지 할 수 있으며 실제로 이것이 서비스를 시작하거나 중지하기 위해 구현 한 유일한 방법입니다. 서비스가 다시 시작되면 다른 장치에 대한 블루투스 연결이 끊어집니다.

연결된 질문의 답변에 따르면 startForeground ()는 "서비스가 종료 될 가능성을 줄이지 만이를 방지하지는 않습니다". 나는 그 사실을 이해하지만,이 문제가없는 다른 앱 (예 : Tasker)의 많은 예를 보았습니다.

사용자가 멈출 때까지 서비스를 실행하지 않으면 내 앱의 유용성이 크게 떨어집니다. 이것을 피할 수있는 방법이 있습니까 ???

서비스가 중지 될 때마다 내 logcat에 다음이 표시됩니다.

ActivityManager: No longer want com.howettl.textab (pid 32321): hidden #16
WindowManager: WIN DEATH: Window{40e2d968 com.howettl.textab/com.howettl.textab.TexTab paused=false
ActivityManager: Scheduling restart of crashed service com.howettl.textab/.TexTabService in 5000ms

편집 : 또한 내가 연결된 다른 장치에서는 발생하지 않는 것 같습니다 : Cyanogen을 실행하는 HTC Legend

편집 : 다음은 출력입니다 adb shell dumpsys activity services.

* ServiceRecord{40f632e8 com.howettl.textab/.TexTabService}

intent={cmp=com.howettl.textab/.TexTabService}

packageName=com.howettl.textab

processName=com.howettl.textab

baseDir=/data/app/com.howettl.textab-1.apk

resDir=/data/app/com.howettl.textab-1.apk

dataDir=/data/data/com.howettl.textab

app=ProcessRecord{40bb0098 2995:com.howettl.textab/10104}

isForeground=true foregroundId=2 foregroundNoti=Notification(contentView=com.howettl.textab/0x1090087 vibrate=null,sound=null,defaults=0x0,flags=0x6a)

createTime=-25m42s123ms lastActivity=-25m42s27ms

 executingStart=-25m42s27ms restartTime=-25m42s124ms

startRequested=true stopIfKilled=false callStart=true lastStartId=1

Bindings:

* IntentBindRecord{40a02618}:

  intent={cmp=com.howettl.textab/.TexTabService}

  binder=android.os.BinderProxy@40a9ff70

  requested=true received=true hasBound=true doRebind=false

  * Client AppBindRecord{40a3b780 ProcessRecord{40bb0098 2995:com.howettl.textab/10104}}

    Per-process Connections:

      ConnectionRecord{40a76920 com.howettl.textab/.TexTabService:@40b998b8}

All Connections:

  ConnectionRecord{40a76920 com.howettl.textab/.TexTabService:@40b998b8}

그리고 출력 adb shell dumpsys activity:

* TaskRecord{40f5c050 #23 A com.howettl.textab}

numActivities=1 rootWasReset=false

affinity=com.howettl.textab

intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.howettl.textab/.TexTab}

realActivity=com.howettl.textab/.TexTab

lastActiveTime=4877757 (inactive for 702s)

* Hist #1: ActivityRecord{40a776c8 com.howettl.textab/.TexTab}

    packageName=com.howettl.textab processName=com.howettl.textab

    launchedFromUid=2000 app=ProcessRecord{40bb0098 2995:com.howettl.textab/10104}

    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.howettl.textab/.TexTab }

    frontOfTask=true task=TaskRecord{40f5c050 #23 A com.howettl.textab}

    taskAffinity=com.howettl.textab

    realActivity=com.howettl.textab/.TexTab

    base=/data/app/com.howettl.textab-1.apk/data/app/com.howettl.textab-1.apk data=/data/data/com.howettl.textab

    labelRes=0x7f060000 icon=0x7f020000 theme=0x0

    stateNotNeeded=false componentSpecified=true isHomeActivity=false

    configuration={ scale=1.0 imsi=0/0 loc=en_CA touch=3 keys=2/1/1 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=6}

    launchFailed=false haveState=true icicle=Bundle[mParcelledData.dataSize=1644]

    state=STOPPED stopped=true delayedResume=false finishing=false

    keysPaused=false inHistory=true visible=false sleeping=true idle=true

    fullscreen=true noDisplay=false immersive=false launchMode=2

    frozenBeforeDestroy=false thumbnailNeeded=false

    connections=[ConnectionRecord{40a76920 com.howettl.textab/.TexTabService:@40b998b8}]

...

Proc #15: adj=prcp /F 40e75070 959:android.process.acore/10006 (provider)

          com.android.providers.contacts/.ContactsProvider2<=Proc{40bb0098 2995:com.howettl.textab/10104}

Proc #16: adj=bak+2/F 40bb0098 2995:com.howettl.textab/10104 (foreground-service)

이는 서비스가 포 그라운드에서 실행되고 있음을 나타냅니다.


좋아요 dokey. 나는 지옥을 겪었고이 문제로 돌아 왔습니다. 진행 방법은 다음과 같습니다. 버그가 있습니다. 이 게시물은 구현에서 버그를 분석하고 문제를 해결하는 방법을 설명합니다.

요약하자면 다음은 작동 방식입니다. 실행중인 서비스는 정기적으로 청소되고 30 분 정도마다 종료됩니다. 이보다 더 오래 살아남 으려는 서비스는 Service.startForeground를 호출하여 알림 표시 줄에 알림을 표시하여 사용자가 서비스가 영구적으로 실행되고 잠재적으로 배터리 수명을 소모하고 있음을 알 수 있도록해야합니다. 주어진 시간에 3 개의 서비스 프로세스 만이 자신을 포 그라운드 서비스로 지정할 수 있습니다. 포 그라운드 서비스가 3 개 이상인 경우 Android는 가장 오래된 서비스를 청소 및 종료 후보로 지정합니다.

안타깝게도 Android에는 다양한 서비스 바인딩 플래그 조합에 의해 트리거되는 포 그라운드 서비스의 우선 순위 지정과 관련하여 버그가 있습니다. 서비스를 포 그라운드 서비스로 올바르게 지정 했어도 프로세스의 서비스에 대한 연결이 특정 결합 플래그 조합으로 이루어진 경우 Android는 어쨌든 서비스를 종료 할 수 있습니다. 자세한 내용은 다음과 같습니다.

포 그라운드 서비스가 필요한 서비스는 거의 없습니다. 일반적으로 사용자가 켜고 끄거나 취소 할 수있는 일종의 인터넷 연결이 지속적으로 활성화되거나 장기적으로 실행되는 경우에만 포 그라운드 서비스가 필요합니다. 포 그라운드 상태가 필요한 서비스의 예 : UPNP 서버, 대용량 파일의 장기 실행 다운로드, Wi-Fi로 파일 시스템 동기화, 음악 재생.

가끔 폴링을하거나 시스템 브로드 캐스트 수신기 또는 시스템 이벤트를 기다리는 경우 타이머에서 서비스를 깨우거나 브로드 캐스트 수신기에 대한 응답으로 서비스를 깨운 다음 ​​서비스가 완료되면 종료하는 것이 좋습니다. 이것이 바로 서비스를 위해 설계된 동작입니다. 단순히 살아남 아야한다면 계속 읽으십시오.

잘 알려진 요구 사항 (예 : Service.startForeground 호출)에 대한 확인란을 선택했으면 다음으로 살펴볼 곳은 Context.bindService 호출에서 사용하는 플래그입니다. 바인딩에 사용되는 플래그는 예기치 않은 다양한 방식으로 대상 서비스 프로세스의 우선 순위에 영향을줍니다. 특히 특정 바인딩 플래그를 사용하면 Android가 포 그라운드 서비스를 정규 서비스로 잘못 다운 그레이드 할 수 있습니다. 프로세스 우선 순위를 지정하는 데 사용되는 코드는 상당히 많이 변경되었습니다. 특히 API 14+에는 이전 바인딩 플래그를 사용할 때 버그를 유발할 수있는 개정이 있습니다. 그리고 4.2.1에는 확실한 버그가 있습니다.

이 모든 것에서 친구는 sysdump 유틸리티로, 활동 관리자가 서비스 프로세스에 할당 한 우선 순위를 파악하고 잘못된 우선 순위를 할당 한 사례를 파악하는 데 사용할 수 있습니다. 서비스를 시작하고 실행 한 후 호스트 컴퓨터의 명령 프롬프트에서 다음 명령을 실행하십시오.

adb 쉘 dumpsys 활동 프로세스> tmp.txt

내용을 검토하려면 메모장 (워드 패드 / 쓰기 아님)을 사용하십시오.

먼저 포 그라운드 상태에서 서비스를 성공적으로 실행했는지 확인하십시오. dumpsys 파일의 첫 번째 섹션에는 각 프로세스의 ActivityManager 속성에 대한 설명이 포함되어 있습니다. dumpsys 파일의 첫 번째 섹션에서 애플리케이션에 해당하는 다음과 같은 행을 찾으십시오.

APP UID 10068 ProcessRecord {41937d40 2205 : tunein.service / u0a10068}

Verify that foregroundServices=true in the following section. Don't worry about the hidden and empty settings; they describe the state of Activities in the process, and don't seem to be particularly relevant for processes with services in them. If foregroundService isn't true, you need to call Service.startForeground to make it true.

The next thing you need to look at is the section near the end of the file titled "Process LRU list (sorted by oom_adj):". Entries in this list allow you to determine whether Android has actually classified your application as a foreground service. If your process is at the bottom of this list, it's a prime candidate for summary extermination. If your process is near the top of the list, it's virtually indestructible.

Let's look at a line in this table:

  Proc #31: adj=prcp /FS trm= 0 2205:tunein.service/u0a10068 (fg-service)

This is an example of a foreground service that's done everything right. The key field here is the "adj=" field. That indicates the priority your process was assigned by the ActivityManagerService after everything was said done. You want it to be "adj=prcp" (visible foreground service); or "adj=vis" (visible process with an activity) or "fore" (process with a foreground activity). If it's "adj=svc" (service process), or "adj=svcb" (legacy service?), or "adj=bak" (empty background process), then your process is a likely candidate for termination, and will be terminated no less frequently than every 30 minutes even if there isn't any pressure to reclaim memory. The remaining flags on the line are mostly diagnostic debug information for Google engineers. Decisions on termination are made based on the adj fields. Briefly, /FS indicates a foreground service; /FA indicates a foreground process with an activity. /B indicates a background service. The label at the end indicates the general rule under which the process was assigned a priority. Usually it should match the adj= field; but the adj= value can be adjusted upward or downward in some cases due to binding flags on active bindings with other services or activities.

If you've tripped over a bug with binding flags, the dumpsys line will look like this:

  Proc #31: adj=bak /FS trm= 0 2205:tunein.service/u0a10068 (fg-service)

Note how the value of the adj field is incorrectly set to "adj=bak" (empty background process), which translates roughly to "please please terminate me now so that I can end this pointless existence" for the purposes of process scavenging. Also note the (fg-service) flag at the end of the line which indicate that "forground service rules were used to determine the "adj" setting. Despite the fact that fg-service rules were used, this process was assigned an adj setting "bak", and it won't live for long. Plainly put, this is a bug.

So the goal is to ensure that your process always gets "adj=prcp" (or better). And the method for achieving that goal is to tweak binding flags until you manage to avoid bugs in the priority assignment.

Here are the bugs I know about. (1) If ANY service or activity has ever bound to the service using Context.BIND_ABOVE_CLIENT, you run the risk that the adj= setting will be downgraded to "bak" even if that binding isn't active any more. This is particularly true if you also have bindings between services. A clear bug in the 4.2.1 sources. (2) Definitely never use BIND_ABOVE_CLIENT for a service-to-service binding. Don't use it for activity-to-service connections either. The flag used to implement BIND_ABOVE_CLIENT behaviour seems to be set on a per-process basis, instead of a per-connection basis, so it triggers bugs with service-to-service bindings even if there isn't an active activity-to-service binding with the flag set. There also seem to be problems with establishing priority when there are multiple services in the process, with service-to-service bindings. Using Context.BIND_WAIVE_PRIORITY (API 14) on service-to-service bindings seems to help. Context.BIND_IMPORTANT seems to be a more-or-less good idea when binding from an Activity to a service. Doing so bumps your process priority one notch higher when the Activity is in the foreground, without doing any apparent harm when the Activity is paused or finished.

But overall, the strategy is to adjust your bindService flags until sysdump indicates that your process has received correct priority.

For my purposes, using Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT for Activity-to-service bindings, and Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY for service-to-service bindings seems to do the right thing. Your mileage may differ.

My app is fairly complex: two background services, each of which may independently hold foreground service states, plus a third which can also take foreground service state; two of the services bind to each other conditionally; the third binds to the first, always. In addition, Activites run in a separate process (makes animation smoother). Running the Activities and Services in the same process didn't seem to make any difference.

Implementation of the rules for scavenging processes, (and source code used to generate the contents of the sysdump files) can be found in the core android file

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java.

Bon chance.

PS: Here's the interpretation of the sysdump strings for Android 5.0. I haven't worked with them, so make of them what you will. I believe you want 4 to be 'A' or 'S', and 5 to be "IF" or "IB", and 1 to be as low as possible (probably below 3, since only 3 three foreground service processes are kept active in default configuration).

Example:
   Proc # : prcp  F/S/IF trm: 0 31719: neirotech.cerebrum.attention:blePrcs/u0a77 (fg-service)

Format:
   Proc # {1}: {2}  {3}/{4}/{5} trm: {6} {7}: {8}/{9} ({10}

1: Order in list: lower is less likely to get trimmed.

2: Not sure.

3:
    B: Process.THREAD_GROUP_BG_NONINTERACTIVE
    F: Process.THREAD_GROUP_DEFAULT

4:
    A: Foreground Activity
    S: Foreground Service
    ' ': Other.

5:
    -1: procState = "N ";
        ActivityManager.PROCESS_STATE_PERSISTENT: procState = "P ";
    ActivityManager.PROCESS_STATE_PERSISTENT_UI:procState = "PU";
    ActivityManager.PROCESS_STATE_TOP: procState = "T ";
    ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: procState = "IF";
    ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: procState = "IB";
    ActivityManager.PROCESS_STATE_BACKUP:procState = "BU";
    ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: procState = "HW";
    ActivityManager.PROCESS_STATE_SERVICE: procState = "S ";
    ActivityManager.PROCESS_STATE_RECEIVER: procState = "R ";
    ActivityManager.PROCESS_STATE_HOME: procState = "HO";
    ActivityManager.PROCESS_STATE_LAST_ACTIVITY: procState = "LA";
    ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: procState = "CA";
    ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: procState = "Ca";
    ActivityManager.PROCESS_STATE_CACHED_EMPTY: procState = "CE";

{6}: trimMemoryLevel

{8} Process ID.
{9} process name
{10} appUid 

If it is saying "no longer want..." then that process does not have a service active in it that is currently in the startForeground() state. Check to make sure your call to that is actually succeeding -- that you are seeing the notification posted, there are no messages in the log at that point complaining about anything, etc. Also use "adb shell dumpsys activity services" to look at the state of your service and make sure it is actually marked as foreground. Also if it is correctly foreground then in the output of "adb shell dumpsys activity" you will see in the section showing the OOM adj of the processes that your process is currently at the foreground level due to that service.

참고URL : https://stackoverflow.com/questions/6645193/foreground-service-being-killed-by-android

반응형