Hizmet bağlamaları ve işlem durumları

Android'deki uygulama işlemleri yalıtılmış olarak bulunmaz. Uygulamalar genellikle diğer uygulamaların veya sistemin kendisi tarafından sağlanan hizmetlerden yararlanır. Bir süreç, hizmet bağlama aracılığıyla başka bir sürece bağlandığında Android çerçevesinin belleği nasıl yönettiğini derinden etkileyen bir bağımlılık oluşturur.

İşlem durumları ve OOM puanları

Android çerçevesi, çalışan her işlemin önemini izlemek için İşlem Durumları'nı kullanır. Bu durumlar daha sonra OomAdjuster tarafından -1000 ile 1000 arasında değişen bir OOM puan ayarlaması (oom_score_adj) değeri atamak için kullanılır.

Daha düşük bir oom_score_adj, işlemin daha önemli olduğu ve Düşük Bellek Sorunu (LMK) tarafından sonlandırılma olasılığının daha düşük olduğu anlamına gelir.

Sık kullanılan işlem durumları

Aşağıdaki tabloda, en yaygın işlem durumlarından bazıları ve bunların tipik oom_score_adj değerleri gösterilmektedir. Tam ve güncel liste için Android kaynak kodundaki android.app.ActivityManager ve com.android.server.am.psc.Constants bölümlerine bakın.

İşlem Durumu (Kıs.) Açıklama Normal oom_score_adj
PER (Kalıcı) Her zaman çalışması gereken sistem işlemleri (ör. Telefon). -800
TOP Kullanıcının şu anda etkileşimde bulunduğu işlem. 0
VIS (Görünür) İşlemde görünür bir etkinlik vardır (ör. yarı saydam bir iletişim kutusunun arkasında). 100
PERC (Algılanabilir) Kullanıcının farkında olduğu arka plan işlemi (ör. müzik çalma). 200
FGS Ön plan hizmetinin barındırıldığı işlem. 0-200 (değişir)
BTOP (Bound Top) TOP başvurusuyla bağlı süreç. 100
BFGS Sınırlı ön plan hizmeti (genellikle sisteme bağlı). 0
PREV (Önceki) Kullanıcının mevcut işlemden önce bulunduğu son işlem. 700
CACHED Güvenli bir şekilde sonlandırılabilen arka plan uygulamaları. 900-999

Hizmet bağlamalarının etkisi

Bir istemci süreci (ör. TOP durumundaki bir uygulama) bir sunucu sürecindeki hizmete bağlandığında, sunucu süreci genellikle daha yüksek bir önceliği devralır. Bu, hizmetin müşteri ihtiyaç duyduğu sürece kullanılabilir kalmasını sağlar.

A sürecinin (TOP) system_server üzerinden bindService() işlevini çağırdığını ve B sürecini BTOP'ye yükselttiğini gösteren şema

BIND işaretleriyle devralmayı kontrol etme

Context.BIND_AUTO_CREATE kullanılırken varsayılan davranış devralmadır. Ancak geliştiriciler, bindService() içindeki çeşitli işaretleri kullanarak bağlamanın hedef işlemin önemini nasıl etkileyeceğini kontrol edebilir.

OOM puanı için önemli BIND işaretleri

Sistem genelinde bellek baskısını yönetirken aşağıdaki işaretler en alakalı olanlardır:

  • BIND_AUTO_CREATE: En yaygın flag. Bu, hizmet sürecinin bağlama olduğu sürece başlatılmasını ve etkin tutulmasını sağlar. Varsayılan olarak, istemciyle eşleşmesi için sunucu işlemi önceliğini de yükseltir.
  • BIND_NOT_FOREGROUND: Hedef hizmetin işleminin ön plana zamanlama önceliğiyle (CPU önceliği) yükseltilmesini engeller. Ancak bu, bellek önceliğinin (oom_score_adj) yükseltilmesine izin vermeye devam eder. Bu, CPU döngüleri için kullanıcı arayüzüyle rekabet etmemesi gereken ancak yine de sonlandırılmaya karşı korunması gereken arka plan çalışmaları için kullanışlıdır.
  • BIND_WAIVE_PRIORITY: Sisteme hedef işlemin planlama veya bellek yönetimi önceliğini etkilememesini söyleyen çok güçlü bir işaret. Hizmet süreci, LRU listesindeki normal bir arka plan süreci gibi yönetilir. Bu nedenle, bağlıyken bile OOM tarafından sonlandırılabilir.
  • BIND_ABOVE_CLIENT: Hizmetin, istemci uygulamasından daha önemli olduğunu gösterir. Sistemin belleği geri kazanması gerektiğinde, bağlı hizmeti sonlandırmadan önce istemci uygulamasını sonlandırmayı tercih eder. Bu, istemci pahasına hizmet için ek bir koruma katmanı sağladığından BIND_AUTO_CREATE'dan "daha güçlüdür".
  • BIND_NOT_PERCEPTIBLE: Hedef hizmetin önemini PERCEPTIBLE düzeyinin altına düşürerek sistemin, daha kritik kullanıcı tarafından algılanabilen işlemler için yer açmak üzere belleğini geri kazanmasına olanak tanır.

Uygulamalı: bağlama etkilerini gözlemleme

TOP uygulamasından gelen bir bağlamanın ayrı bir işlemin durumunu nasıl etkilediğini göstermek için MemoryLab uygulamasını kullanacağız.

1. MemoryLab'i başlatma

Aşağıdaki komut uygulamayı başlatır. Uygulama açıldıktan sonra ön planda kaldığından emin olun (henüz Ana Sayfa düğmesine basmayın veya uygulamalar arasında geçiş yapmayın).

adb shell am start -n com.android.memorylab/.MainActivity

2. İşlemleri belirleme

Bağlama işleminden önce süreç durumlarını kontrol edin. MemoryLab, ana kullanıcı arayüzünü tek bir işlemde çalıştırır ve :remote işleminde çalışan bir RemoteService içerir.

adb shell dumpsys activity processes com.android.memorylab

Örnek çıkış snippet'i:

  Process OOM control (154 total, non-act at 7, non-svc at 7):
    Proc #0: fg       T/A/TOP  LCMNFUATI  t: 0 13470:com.android.memorylab/u0a417 (top-activity)
        oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
        state: cur=TOP  set=TOP   lastRss=0.00 lastCachedRss=0.00

Ana işlemin com.android.memorylab TOP durumunda olduğunu görürsünüz. :remote işlemi henüz başlatılmadı.

3. Tetikleyici bağlama

Hizmet bağlamayı tetiklemek için uygulamaya bir yayın gönderin:

adb shell am broadcast -a com.android.memorylab.LEAK_BINDER

4. Yükseltilmiş durumu gözlemleme

İşlem durumlarını tekrar kontrol edin:

adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"

Örnek çıkış snippet'i:

  Proc #  1: vis      F/ /BTOP ---NFUATI  t: 0 13560:com.android.memorylab:remote/u0a417 (service)
    com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
    oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
    state: cur=BTOP set=BTOP  lastRss=0.00 lastCachedRss=0.00

:remote işlemi şu anda çalışıyor ve 100 oom_score_adj ile BTOP (Bound TOP) durumunda. Bu, normal bir arka plan hizmetinden (500 veya daha yüksek bir seviyede olur) çok daha fazla korunur. <=Proc{...} gösterimi, bu öncelik yükseltmesinden hangi sürecin sorumlu olduğunu gösterir.

5. Arka plana gönder

Cihazdaki HOME (ANA EKRAN) düğmesine basın. Durumları tekrar kontrol edin:

adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"

Örnek çıkış snippet'i:

    Proc #  2: prev     b/ /LAST --------I  t: 0 13560:com.android.memorylab:remote/u0a417 (service)
        com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
        oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
        state: cur=LAST set=LAST  lastRss=0.00 lastCachedRss=0.00
    Proc #  1: prev     b/ /LAST --------I  t: 0 13470:com.android.memorylab/u0a417 (previous)
        oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
        state: cur=LAST set=LAST  lastRss=209MB lastCachedRss=0.00

İstemci işlemi artık TOP olmadığı için her iki işlem de daha düşük öncelikli bir duruma (PREV / oom_score_adj 700) geçti. (Not: Durum dökümündeki LAST, LAST_ACTIVITY dahili durumu ifade eder ve üst düzey özetlerde PREV ile eşleşir).

procstats ile analiz etme

procstats aracı, bu durumların geçmişteki görünümünü sağlar.

# View stats for MemoryLab over the last hour
adb shell dumpsys procstats --hours 1 com.android.memorylab

Örnek çıkış snippet'i:

  *   com.android.memorylab / u0a417 / v37:
      *   Prc com.android.memorylab / u0a417 / v37:
             TOTAL: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
               Top: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
      *   Prc com.android.memorylab:remote / u0a417 / v37:
             TOTAL: 0.19%
           Bnd Top: 0.19%

Burada Bnd Top, uzak işlemin TOP durumundaki bir uygulamaya bağlı olarak geçirdiği sürenin yüzdesini gösterir.

Bağlamaları Perfetto ile yakalama ve analiz etme

dumpsys size anlık bir görüntü sunarken Perfetto, bağlamanın gerçekleştiği anı ve OOM puanının gerçek zamanlı olarak nasıl değiştiğini görmenizi sağlar.

1. İz kaydetme

linux.process_stats ve am atrace kategorisini içeren bir yapılandırma kullanın:

adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/service_bindings.perfetto-trace <<EOF
buffers: { size_kb: 65536 }
data_sources: {
    config {
        name: "linux.process_stats"
        process_stats_config { proc_stats_poll_ms: 100 }
    }
}
data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config { ftrace_events: "am/am_proc_bound" }
    }
}
duration_ms: 15000
EOF

2. Sorgu OOM puanı geçişleri

PerfettoSQL'i kullanarak uzak işlemin OOM puanının kullanıcı arayüzü işlemine göre nasıl değiştiğini görebilirsiniz:

SELECT ts, p.name, value AS oom_score_adj
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name LIKE 'com.android.memorylab%'
  AND t.name = 'oom_score_adj'
ORDER BY ts;

3. Bağlama etkinliklerini belirleme

Bağlama bağımlılığının tam olarak ne zaman oluşturulduğunu ve hangi işlemin başlattığını görmek için şu sorguyu kullanın:

SELECT
    s.ts,
    p.name AS process_name,
    t.name AS thread_name,
    s.name AS slice_name
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE s.name LIKE 'bindService:{com.android.memorylab%';

Sistemden uygulamaya bağlantılar

Android sisteminin kendisi, temel işlevleri sağlamak için genellikle üçüncü taraf uygulamalarındaki hizmetlere bağlanır. Bu bağlamaların amacı genellikle gecikmeyi azaltmaktır. Sistem, bir işlemi canlı ve bellekte tutarak kritik bir kullanıcı etkileşimi gerçekleştiğinde "soğuk başlatma"nın (APK'yı yükleme, çalışma zamanını başlatma ve Application nesnesini oluşturma) maliyetli ek yükünü önler. Arka plan etkinlikleri akışlarını işlemesi gereken uygulamalarda sık sık soğuk başlatma yapılmasını önlemek için başka bağlamalar da vardır.

Tipik bir cihazda gözlemleyebileceğiniz gerçek hayattan bazı örnekleri aşağıda bulabilirsiniz:

VoiceInteractor

Kullanıcılar, dijital asistanın telefonlarının işletim sistemine yerleştirilmesini, konuşulan bir etkinleştirme kelimesi veya hızlı bir giriş hareketiyle anında çağrılabilmesini ve etkileşimin sorunsuz olmasını bekler.

Bir asistan tetikleyici olayı (ör. Google Pixel telefonlarda "Ok Google" özel kelimesi) gerçekleştiğinde dijital asistanın anında yanıt vermesi gerekir. Bunu sağlamak için system_server, kullanıcının seçtiği sesli etkileşim hizmeti ile kalıcı bir bağlama oluşturur.

system_server'ın Google Uygulaması'nın etkileşimci sürecine bağlandığını gösteren diyagram

İşlem durumlarını kontrol ederseniz (ör.dumpsys activity processes kullanarak) BFGS (Bound Foreground Service) durumunda com.google.android.googlequicksearchbox:interactor gibi bir işlem görebilirsiniz. Bu işlem, system_server (UID 1000) tarafından yapılan bir bağlama ile canlı tutulur.

NotificationListenerService

Bazı sistemden uygulamaya bağlamalarda amaç gecikmeyi azaltmak değil, sık sık soğuk başlatmayı önlemektir. NotificationListenerService, yeni bildirimler yayınlandığında veya kaldırıldığında sistemden gelen çağrıları alan bir hizmet, bunun en iyi örneğidir. Tipik bir akıllı telefon kullanıcısı gün boyunca yüzlerce bildirim alabilir. Sistem bir bildirim dinleyiciden ayrılırsa bu uygulamanın işlemi büyük olasılıkla önbelleğe alınmış duruma geçer ve LMK tarafından sonlandırılabilir.

Birkaç saniye sonra bir sonraki bildirim geldiğinde sistem, etkinliği iletmek için uygulamanın sürecini baştan başlatmak zorunda kalır. Bu sürekli sonlandırma ve soğuk başlatma döngüsü, işlemi arka planda bağlı ve etkin tutmaktan çok daha fazla CPU ve pil gücü tüketir.

Başlatıcının "-1 ekranı " (haber feed'i)

Modern başlatıcı uygulamaları genellikle temel gezinme işlevini (ana sayfa simgeleri ve widget'lar) başlatıcı ekranlarından birinde kullanılabilen ve başlatıcı kullanıcı deneyimiyle sorunsuz bir şekilde entegre edilmiş bir haber feed'iyle birleştirir. Haber feed'i başka bir uygulama tarafından sağlanabilir. Örneğin, Google Pixel'de Başlatıcı, Google uygulaması tarafından sağlanan bir feed ile entegre olur.

Haber feed'ini görüntülemek için ana ekranınızda sola kaydırdığınızda geçiş sorunsuz olmalıdır. Başlatıcı, haber feed'ini sağlayan uygulamadaki bir hizmet arayüzüne bağlanarak ve bu bağlantıyı başlatıcı çalıştığı sürece canlı tutarak bunu başarır. Bu sayede, siz bakmıyor olsanız bile feed içeriği oluşturulmuş ve bellekte hazır durumda kalır.

Diğer yaygın örnekler

  • Başlatıcı (HOME_APP_ADJ): Başlatıcı uygulamasının (Ana Sayfa) öncelik listesinde kendine ait özel bir yeri vardır. Her zaman bir hizmetle sınırlı olmasa da HOME_APP_ADJ (genellikle 600) değeri atanır. Sistem, kullanıcının sık sık geri döndüğü için başlatıcıyı etkin tutmayı tercih eder. Aslında, başlatıcıyı kapatmak herhangi bir uygulamadan çıkarken kullanıcının başlatıcının soğuk başlatılmasını beklemesi gerekeceğinden yavaş bir kullanıcı deneyimine neden olacağından sistem, başlatıcıyı kapatmak yerine daha önce kullanılan uygulamayı (PREV_APP_ADJ = 700) kapatmayı tercih eder.
  • Giriş Yöntemi Düzenleyici (IME): Yazarken sistem, seçtiğiniz klavye uygulamasına (ör. Gboard) bağlanır. Bu, klavye geçici olarak gizlense bile klavye işleminin yükseltilmiş durumda kalmasını sağlar. Bu ayar, başka bir metin alanına dokunduğunuzda klavyenin anında yeniden görünmesini sağlar.
  • NFC ile Ödemeler: Ödeme yapmak için telefonunuza dokunduğunuzda sistem, NFC ile ödeme hizmetine (ör. Google Cüzdan) bağlanır. Bu işlemler genellikle satıcı terminalinden katı anlık işlem koşulları gerektirir. Ödeme uygulamasının sıfırdan başlatılması gerekiyorsa işlemin zaman aşımına uğrayıp başarısız olması mümkündür.

Tavizler ve performans düşüşü

Bağlamalar performans ve doğruluk için gerekli olsa da sistemin bellek sağlığına zarar verir.

  • Esnekliğin Azalması: Bağlı her işlem, LMK'nin kolayca sonlandıramayacağı bir işlemdir. Bu, sistemin baskı altında belleği boşaltmak için kullanabileceği önbelleğe alınmış işlemlerin "yastığını" azaltır.
  • Performans düşüşünü kötüleştirme: Çok fazla işlem bağlıysa sistem, sonlandırılabilir arka plan işlemi neredeyse hiç kalmamış bir durumda olabilir. Bellek baskısı arttığında sistem, daha önemli işlemleri sonlandırmak veya sayfa önbelleğini boşaltmak zorunda kalacağından "performans uçurumundan" çok daha hızlı düşer.

← Yerel | ↑ Yukarı | Sistem genelinde →