42

У меня есть вопрос о wakelock. В случаях, показанных ниже, освобождает ли релиз wakeelock для ОС Android (PARTIAL_WAKE_LOCK), чтобы предотвратить использование wakelock и растрачивание батареи до выключения питания (не спящего режима).Выпускает ли ОС Android Wakelock, если приложение или служба, содержащая его, будут убиты?

Case 1-а:
App приобрела wakelock (без опции таймаута) в одном из своих нитей (пожалуйста, думаю, что это разумно в данном случае), и он был разработан, чтобы освободить wakelock, когда важнейшей задачей было законченный. Приложение может быть убито диспетчером задач или пресловутым taskkiller, и приложение не имеет шансов позволить его потоку освободить wakelock. Что происходит с этим вакелоком?

Случай 1-б:
(. Если ответ на случай 1-а «Да, не беспокойтесь», то, пожалуйста, игнорировать этот случай) То же случае 1-а, но приложение дал тайм-аут вариант на wakelock, скажем, 3 секунды. Этот параметр тайм-аута остается в силе?

Case 2-а:
Пожалуйста, представьте себе есть услуга, которая была начата AlarmManager (через широковещательный приемник) и служба приобрела wakelock (без опции тайм-аута). Эта услуга предназначена для того, чтобы сделать минимум времени, достигнутого в wakelock. Но, к сожалению, Android OS выбрала эту службу для убийства из-за нехватки памяти. (Я не знаю, будет ли ОС не убивать службу при приобретении wakelock, но я думаю, OS не заботится. Но я надеюсь, что ОС выпустит wakelock позже.) Что происходит с этим wakelock?

Случай 2-б:
(. Если ответ на случай 2-а «Да, не беспокойтесь», то, пожалуйста, игнорировать этот случай) То же случае 2-а, но службы дали тайм-аут вариант на wakelock, скажем, 3 секунды. Этот параметр тайм-аута остается в силе?

ответ

43

Обзор реализации WakeLock

Когда мы используем pm.newWakeLock для создания нового wakelock, то PowerManager просто создает новый объект WakeLock и возвращается. Объект WakeLock не является связующим объектом, поэтому он не может использоваться несколькими процессами. Однако в этом объекте WakeLock он содержит объект Binder с именем mToken.

WakeLock(int flags, String tag) { 
     mFlags = flags; 
     mTag = tag; 
     mToken = new Binder(); 
    } 

Так что, когда вы звоните приобрести или выпустить на этом WakeLock объект, он фактически передает этот маркер PowerManagerService.

private void acquireLocked() { 
     if (!mRefCounted || mCount++ == 0) { 
      mHandler.removeCallbacks(mReleaser); 
      try { 
       mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource); 
      } catch (RemoteException e) { 
      } 
      mHeld = true; 
     } 
    } 

Посмотрите, как PowerManagerService работает при приобретении или освобождение wakelock поможет вам ответить на ваш вопрос.

void acquireWakeLockInternal(IBinder lock, int flags, String tag, WorkSource ws, 
     int uid, int pid) { 
    synchronized (mLock) { 
     ... 
     WakeLock wakeLock; 
     int index = findWakeLockIndexLocked(lock); 
     if (index >= 0) { 
      ... 
      // Update existing wake lock. This shouldn't happen but is harmless. 
      ... 
     } else { 
      wakeLock = new WakeLock(lock, flags, tag, ws, uid, pid); 
      try { 
       lock.linkToDeath(wakeLock, 0); 
      } catch (RemoteException ex) { 
       throw new IllegalArgumentException("Wake lock is already dead."); 
      } 
      notifyWakeLockAcquiredLocked(wakeLock); 
      mWakeLocks.add(wakeLock); 
     } 
     ... 
    } 
    ... 
} 

Ключевым заявлением является lock.linkToDeath(wakeLock, 0);. То, что lock - это точно mToken, о котором мы упоминали ранее. Этот метод регистрирует получателя (wakeLock) для уведомления, если это связующее вещество уходит.Если этот предмет связующего неожиданно исчезнет (как правило, потому, что его хостинг-процесс был убит), тогда получатель вызовет метод binderDied.

Обратите внимание, что WakeLock в PowerManagerService отличается от WakeLock в PowerManager, это реализация IBinder.DeathRecipient. Поэтому ознакомьтесь с его методом binderDied.

@Override 
    public void binderDied() { 
     PowerManagerService.this.handleWakeLockDeath(this); 
    } 

handleWakeLockDeath выпустит эту wakelock.

private void handleWakeLockDeath(WakeLock wakeLock) { 
    synchronized (mLock) { 
     ... 
     int index = mWakeLocks.indexOf(wakeLock); 
     if (index < 0) { 
      return; 
     } 

     mWakeLocks.remove(index); 
     notifyWakeLockReleasedLocked(wakeLock); 

     applyWakeLockFlagsOnReleaseLocked(wakeLock); 
     mDirty |= DIRTY_WAKE_LOCKS; 
     updatePowerStateLocked(); 
    } 
} 

Так что я думаю, что в обоих случаях в вашем вопросе ответ не беспокоится. По крайней мере, в Android 4.2 (откуда приходит код) это правда. Кроме того, существует метод финализации класса WakeLock в PowerManager, но это не является ключом к вашему вопросу.

+4

Благодарим вас за подробный, ясный ответ на этот 2-летний вопрос. Ваш ответ определенно помогает многим разработчикам, включая меня. – Tomcat

+1

С удовольствием, я не знаю, почему этот старый вопрос прыгнул на самое первое место в списке вопросов, отсортированном по интересному. @Кот – StarPinkER

6

Я бы предположил (я не знаю этого наверняка), система Android не поддерживает wakelocks для убитых процессов. Скорее всего, когда он убивает процесс с помощью sigkill, он также удаляет любые wakelocks, удерживаемые этим процессом.

В противном случае, как вы говорите, аварии приведут к тому, что телефон будет всегда бодрствовать, чего я не наблюдал.

+0

Это звучит разумно для меня. Думаю ты прав. Надеюсь, SDK четко описывает это поведение. – Tomcat

+0

Я также нашел, что таймаут для wakelock имеет ошибку [link] http://code.google.com/p/android/issues/detail?id=14184, поэтому мы не можем использовать его эффективным способом. (Я попробовал его с OS2.2 и не смог, затем Google привел к этой ссылке.) – Tomcat

+1

Простым тестом было бы сделать приложение, которое устанавливает экран сохранения на wakelock, а затем кнопку в приложении, которая намеренно вызывает FC. Затем просто подождите и посмотрите, выключен экран или нет. –