सेवाओं को लिंक करने और प्रोसेस करने की स्थितियां

Android पर ऐप्लिकेशन प्रोसेस, अलग-अलग नहीं होती हैं. ऐप्लिकेशन अक्सर, अन्य ऐप्लिकेशन या सिस्टम की ओर से दी जाने वाली सेवाओं पर निर्भर होते हैं. जब कोई प्रोसेस, सर्विस बाइंडिंग के ज़रिए किसी दूसरी प्रोसेस से कनेक्ट होती है, तो इससे एक डिपेंडेंसी बनती है. इसका Android फ़्रेमवर्क के मेमोरी मैनेजमेंट पर काफ़ी असर पड़ता है.

प्रोसेस की स्थितियां और ओओएम स्कोर

Android फ़्रेमवर्क, हर रनिंग प्रोसेस की अहमियत को ट्रैक करने के लिए प्रोसेस स्टेट का इस्तेमाल करता है. इसके बाद, इन स्थितियों का इस्तेमाल OomAdjuster करता है, ताकि OOM स्कोर में बदलाव (oom_score_adj) की वैल्यू असाइन की जा सके. यह वैल्यू -1000 से 1000 के बीच होती है.

oom_score_adj की वैल्यू कम होने का मतलब है कि प्रोसेस ज़्यादा ज़रूरी है और Low Memory Killer (एलएमके) के ज़रिए इसे बंद किए जाने की संभावना कम है.

प्रोसेस की सामान्य स्थितियां

यहां दी गई टेबल में, प्रोसेस की कुछ सामान्य स्थितियां और उनकी सामान्य oom_score_adj वैल्यू दिखाई गई हैं. पूरी और अप-टू-डेट सूची देखने के लिए, Android के सोर्स कोड में मौजूद android.app.ActivityManager और com.android.server.am.psc.Constants देखें.

प्रोसेस की स्थिति (संक्षिप्त नाम) ब्यौरा औसत oom_score_adj
PER (परसिस्टेंट) सिस्टम प्रोसेस, जिन्हें हमेशा चालू रहना चाहिए. जैसे, टेलीफ़ोनी. -800
TOP वह प्रोसेस जिससे उपयोगकर्ता फ़िलहाल इंटरैक्ट कर रहा है. 0
VIS (दिख रहा है) इस प्रोसेस में कोई गतिविधि दिख रही हो. जैसे, पारदर्शी डायलॉग के पीछे. 100
PERC (Perceptible) बैकग्राउंड में चल रही ऐसी प्रोसेस जिसके बारे में उपयोगकर्ता को पता है. जैसे, संगीत चलाना. 200
FGS फ़ोरग्राउंड सेवा को होस्ट करने वाला प्रोसेस. 0 से 200 (बदलता रहता है)
BTOP (बाउंड टॉप) यह प्रोसेस, टीओपी ऐप्लिकेशन से जुड़ी है. 100
BFGS बाउंड फ़ोरग्राउंड सेवा (आम तौर पर सिस्टम से जुड़ी होती है). 0
PREV (पिछला) मौजूदा प्रोसेस से पहले, उपयोगकर्ता जिस प्रोसेस में था. 700
CACHED बैकग्राउंड में चल रहे ऐसे ऐप्लिकेशन जिन्हें सुरक्षित तरीके से बंद किया जा सकता है. 900 से 999

सेवाओं को लिंक करने का असर

जब कोई क्लाइंट प्रोसेस (जैसे, TOP स्थिति में मौजूद कोई ऐप्लिकेशन) किसी सर्वर प्रोसेस में मौजूद सेवा से जुड़ता है, तो सर्वर प्रोसेस को अक्सर ज़्यादा प्राथमिकता मिलती है. इससे यह पक्का किया जाता है कि क्लाइंट को जब तक सेवा की ज़रूरत है, तब तक वह उपलब्ध रहे.

इस डायग्राम में, प्रोसेस A (TOP) को system_server के ज़रिए bindService() को कॉल करते हुए दिखाया गया है. साथ ही, प्रोसेस B को BTOP पर अपग्रेड करते हुए दिखाया गया है

BIND फ़्लैग की मदद से इनहेरिटेंस को कंट्रोल करना

Context.BIND_AUTO_CREATE का इस्तेमाल करने पर, इनहेरिटेंस डिफ़ॉल्ट रूप से लागू होता है. हालांकि, डेवलपर यह कंट्रोल कर सकते हैं कि बाइंडिंग से टारगेट प्रोसेस की अहमियत पर कैसे असर पड़ता है. इसके लिए, bindService() में मौजूद अलग-अलग फ़्लैग का इस्तेमाल किया जा सकता है.

OOM स्कोर के लिए मुख्य BIND फ़्लैग

सिस्टम-वाइड मेमोरी प्रेशर को मैनेज करने के लिए, ये फ़्लैग सबसे ज़्यादा काम के होते हैं:

  • BIND_AUTO_CREATE: यह सबसे ज़्यादा इस्तेमाल किया जाने वाला फ़्लैग है. इससे यह पक्का किया जाता है कि सेवा की प्रोसेस शुरू हो गई है और जब तक बाइंडिंग मौजूद है, तब तक यह चालू रहेगी. डिफ़ॉल्ट रूप से, यह सर्वर प्रोसेस की प्राथमिकता को भी क्लाइंट से मैच करने के लिए बढ़ाता है.
  • BIND_NOT_FOREGROUND: इससे टारगेट सेवा की प्रोसेस को फ़ोरग्राउंड शेड्यूलिंग प्राथमिकता (सीपीयू प्राथमिकता) पर नहीं ले जाया जा सकता. हालांकि, इससे मेमोरी की प्राथमिकता (oom_score_adj) को अब भी बढ़ाया जा सकता है. यह बैकग्राउंड में किए जाने वाले ऐसे काम के लिए फ़ायदेमंद है जिसमें सीपीयू साइकल के लिए यूज़र इंटरफ़ेस (यूआई) से प्रतिस्पर्धा नहीं करनी चाहिए. हालांकि, इसे बंद होने से बचाया जाना चाहिए.
  • BIND_WAIVE_PRIORITY: यह एक बहुत ही अहम फ़्लैग है. यह सिस्टम को निर्देश देता है कि टारगेट प्रोसेस की शेड्यूलिंग या मेमोरी मैनेजमेंट की प्राथमिकता पर असर न पड़े. इस सेवा की प्रोसेस को इस तरह मैनेज किया जाएगा जैसे कि यह LRU सूची में मौजूद कोई सामान्य बैकग्राउंड प्रोसेस हो. इससे यह सेवा, बाइंड होने के दौरान भी OOM किलिंग के लिए उपलब्ध हो जाएगी.
  • BIND_ABOVE_CLIENT: इससे पता चलता है कि सेवा, क्लाइंट ऐप्लिकेशन से ज़्यादा ज़रूरी है. जब सिस्टम को मेमोरी वापस पाने की ज़रूरत होती है, तो वह बाउंड सर्विस को बंद करने से पहले क्लाइंट ऐप्लिकेशन को बंद कर देगा. यह BIND_AUTO_CREATE से "ज़्यादा सुरक्षित" है, क्योंकि यह क्लाइंट की कीमत पर सेवा के लिए सुरक्षा की एक अतिरिक्त लेयर उपलब्ध कराता है.
  • BIND_NOT_PERCEPTIBLE: इससे टारगेट की गई सेवा की अहमियत को PERCEPTIBLE लेवल से नीचे कर दिया जाता है. इससे सिस्टम को अपनी मेमोरी वापस पाने में मदद मिलती है, ताकि वह उपयोगकर्ता के लिए ज़्यादा ज़रूरी प्रोसेस के लिए जगह बना सके.

हाथों-हाथ: बाइंडिंग के असर को देखना

हम MemoryLab ऐप्लिकेशन का इस्तेमाल करके यह दिखाएँगे कि TOP ऐप्लिकेशन से की गई बाइंडिंग, किसी दूसरी प्रोसेस की स्थिति पर कैसे असर डालती है.

1. MemoryLab लॉन्च करें

इस कमांड से ऐप्लिकेशन लॉन्च होता है. ऐप्लिकेशन खुलने के बाद, पक्का करें कि ऐप्लिकेशन फ़ोरग्राउंड में ही रहे. अभी होम बटन न दबाएं या ऐप्लिकेशन स्विच न करें.

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

2. प्रोसेस की पहचान करना

बाइंड करने से पहले, प्रोसेस की स्थितियां देखें. MemoryLab अपना मुख्य यूज़र इंटरफ़ेस (यूआई) एक प्रोसेस में चलाता है. साथ ही, इसमें एक RemoteService होता है, जो :remote प्रोसेस में चलता है.

adb shell dumpsys activity processes com.android.memorylab

आउटपुट स्निपेट का उदाहरण:

  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

आपको मुख्य प्रोसेस com.android.memorylab, TOP स्थिति में दिखेगी. :remote प्रोसेस अभी शुरू नहीं हुई है.

3. ट्रिगर बाइंडिंग

सेवा को बाइंड करने के लिए, ऐप्लिकेशन को ब्रॉडकास्ट भेजें:

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

4. बढ़ी हुई स्थिति को मॉनिटर करना

प्रोसेस की स्थितियों की फिर से जांच करें:

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

आउटपुट स्निपेट का उदाहरण:

  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 प्रोसेस अब चल रही है और BTOP (बाउंड टीओपी) स्थिति में है. साथ ही, oom_score_adj की वैल्यू 100 है. यह सामान्य बैकग्राउंड में चलने वाली सेवा (जो 500 या इससे ज़्यादा पर होगी) की तुलना में ज़्यादा सुरक्षित है. <=Proc{...} नोटेशन से पता चलता है कि प्राथमिकता बढ़ाने के लिए कौनसी प्रोसेस ज़िम्मेदार है.

5. बैकग्राउंड में चलाएं

डिवाइस पर मौजूद HOME बटन दबाएं. राज्यों के नाम की फिर से जांच करें:

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

आउटपुट स्निपेट का उदाहरण:

    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

अब दोनों प्रोसेस को कम प्राथमिकता वाली स्थिति (PREV / oom_score_adj 700) में बदल दिया गया है, क्योंकि क्लाइंट प्रोसेस अब TOP नहीं है. (ध्यान दें: स्टेट डंप में LAST का मतलब LAST_ACTIVITY इंटरनल स्टेट से है, जो ज़्यादा जानकारी वाली खास जानकारी में PREV से मैप होती है).

procstats की मदद से विश्लेषण करना

procstats टूल, इन राज्यों की पुरानी स्थिति के बारे में जानकारी देता है.

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

आउटपुट स्निपेट का उदाहरण:

  *   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%

यहां, Bnd Top से पता चलता है कि रिमोट प्रोसेस को TOP स्थिति में किसी ऐप्लिकेशन से कितने प्रतिशत समय के लिए बाइंड किया गया था.

Perfetto की मदद से बाइंडिंग कैप्चर करना और उनका विश्लेषण करना

dumpsys से आपको स्नैपशॉट मिलता है, जबकि Perfetto से आपको यह पता चलता है कि बाइंडिंग कब हुई और ओओएम स्कोर में रीयल-टाइम में कैसे बदलाव हुआ.

1. ट्रेस रिकॉर्ड करना

ऐसे कॉन्फ़िगरेशन का इस्तेमाल करें जिसमें linux.process_stats और am atrace कैटगरी शामिल हो:

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. क्वेरी के ओओएम स्कोर में बदलाव

PerfettoSQL का इस्तेमाल करके, यह देखा जा सकता है कि यूज़र इंटरफ़ेस (यूआई) प्रोसेस के मुकाबले, रिमोट प्रोसेस का ओओएम स्कोर कैसे बदला:

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. बाइंडिंग इवेंट की पहचान करना

यह देखने के लिए कि बाइंडिंग डिपेंडेंसी कब सेट की गई थी और इसे किस प्रोसेस ने शुरू किया था, इस क्वेरी का इस्तेमाल करें:

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%';

सिस्टम से ऐप्लिकेशन बाइंडिंग

Android सिस्टम, अक्सर तीसरे पक्ष के ऐप्लिकेशन में मौजूद सेवाओं से जुड़ता है, ताकि मुख्य फ़ंक्शन उपलब्ध कराए जा सकें. इन बाइंडिंग का मकसद अक्सर लेटेंसी को कम करना होता है. किसी प्रोसेस को चालू रखने और मेमोरी में सेव रखने से, सिस्टम को "कोल्ड स्टार्ट" (एपीके लोड करना, रनटाइम शुरू करना, और ऐप्लिकेशन ऑब्जेक्ट बनाना) के महंगे ओवरहेड से बचने में मदद मिलती है. ऐसा तब होता है, जब उपयोगकर्ता कोई ज़रूरी इंटरैक्शन करता है. अन्य बाइंडिंग मौजूद हैं, ताकि बैकग्राउंड इवेंट की स्ट्रीम को मैनेज करने वाले ऐप्लिकेशन के लिए, बार-बार कोल्ड स्टार्ट न हो.

यहां कुछ ऐसे उदाहरण दिए गए हैं जिन्हें किसी सामान्य डिवाइस पर देखा जा सकता है:

VoiceInteractor

उपयोगकर्ताओं को उम्मीद होती है कि डिजिटल असिस्टेंट उनके फ़ोन के ओएस में पहले से मौजूद हो, ताकि वे बोलकर या तुरंत इनपुट करके उसे चालू कर सकें. साथ ही, वे यह भी चाहते हैं कि असिस्टेंट के साथ उनका इंटरैक्शन आसान और बिना किसी रुकावट के हो.

जब असिस्टेंट ट्रिगर होती है (जैसे, Google Pixel फ़ोन पर "OK Google" हॉटवर्ड), तो डिजिटल असिस्टेंट को तुरंत जवाब देना होता है. यह पक्का करने के लिए, system_server आवाज़ से इंटरैक्ट करने की सेवा से हमेशा के लिए जुड़ा रहता है. यह सेवा, उपयोगकर्ता चुनता है.

सिस्टम_सर्वर को Google ऐप्लिकेशन की इंटरैक्टर प्रोसेस से बाइंड करने वाला डायग्राम

अगर प्रोसेस की स्थितियों की जांच की जाती है (जैसे, dumpsys activity processes का इस्तेमाल करके), तो आपको BFGS (बाउंड फ़ोरग्राउंड सेवा) स्थिति में com.google.android.googlequicksearchbox:interactor जैसी प्रोसेस दिख सकती है. इसे system_server (यूआईडी 1000) से बाइंड करके चालू रखा जाता है.

NotificationListenerService

सिस्टम से ऐप्लिकेशन के बीच कुछ बाइंडिंग के लिए, इंतज़ार का समय कम करना ज़रूरी नहीं होता. इसके बजाय, बार-बार कोल्ड स्टार्ट होने से रोकना ज़रूरी होता है. NotificationListenerService, इसका सबसे अच्छा उदाहरण है. यह एक ऐसी सेवा है जिसे सिस्टम से कॉल तब मिलते हैं, जब नई सूचनाएं पोस्ट की जाती हैं या हटाई जाती हैं. स्मार्टफ़ोन इस्तेमाल करने वाले किसी व्यक्ति को पूरे दिन में सैकड़ों सूचनाएं मिल सकती हैं. अगर सिस्टम किसी सूचना लिसनर से अनबाउंड हो जाता है, तो उस ऐप्लिकेशन की प्रोसेस, कैश मेमोरी में सेव की गई स्थिति में चली जाएगी. साथ ही, LMK उसे बंद कर सकता है.

जब अगली सूचना मिलती है, तो सिस्टम को ऐप्लिकेशन की प्रोसेस को फिर से कोल्ड स्टार्ट करना पड़ता है. ऐसा इसलिए, ताकि वह इवेंट की सूचना दे सके. प्रोसेस को बार-बार बंद करने और फिर से शुरू करने से, सीपीयू और बैटरी की खपत बहुत ज़्यादा होती है. इसके बजाय, प्रोसेस को बैकग्राउंड में चालू रखने से सीपीयू और बैटरी की खपत कम होती है.

लॉन्चर की "-1 स्क्रीन" (न्यूज़ फ़ीड)

आधुनिक लॉन्चर ऐप्लिकेशन में, आम तौर पर नेविगेशन की मुख्य सुविधा (होम आइकॉन और विजेट) के साथ-साथ एक न्यूज़ फ़ीड भी होता है. यह न्यूज़ फ़ीड, लॉन्चर की किसी एक स्क्रीन पर उपलब्ध होता है और लॉन्चर के यूज़र एक्सपीरियंस (यूएक्स) के साथ आसानी से इंटिग्रेट हो जाता है. ऐसा हो सकता है कि न्यूज़ फ़ीड किसी दूसरे ऐप्लिकेशन से मिला हो. उदाहरण के लिए, Google Pixel पर लॉन्चर, Google ऐप्लिकेशन से मिले फ़ीड के साथ इंटिग्रेट होता है.

होम स्क्रीन पर बाईं ओर स्वाइप करके, न्यूज़ फ़ीड देखते समय ट्रांज़िशन आसानी से होना चाहिए. लॉन्चर, इस काम को ऐप्लिकेशन में मौजूद सेवा इंटरफ़ेस से बाइंड करके पूरा करता है. यह ऐप्लिकेशन, न्यूज़ फ़ीड उपलब्ध कराता है. लॉन्चर के चालू रहने तक, यह बाइंडिंग चालू रहती है. इससे फ़ीड का कॉन्टेंट रेंडर होता रहता है और मेमोरी में सेव रहता है. ऐसा तब भी होता है, जब फ़ीड नहीं देखा जा रहा हो.

अन्य सामान्य उदाहरण

  • लॉन्चर (HOME_APP_ADJ): लॉन्चर ऐप्लिकेशन (Home) को प्राथमिकता सूची में खास स्लॉट मिलता है. हालांकि, यह हमेशा किसी सेवा से नहीं जुड़ा होता है, लेकिन इसे HOME_APP_ADJ (आम तौर पर 600) असाइन किया जाता है. सिस्टम, लॉन्चर को चालू रखने की कोशिश करता है, क्योंकि उपयोगकर्ता अक्सर इसका इस्तेमाल करता है. असल में, सिस्टम पहले से इस्तेमाल किए जा रहे ऐप्लिकेशन (PREV_APP_ADJ = 700) को बंद करना पसंद करेगा, न कि लॉन्चर को. ऐसा इसलिए, क्योंकि लॉन्चर को बंद करने से, किसी भी ऐप्लिकेशन से बाहर निकलते समय उपयोगकर्ता को धीमा अनुभव मिलेगा. ऐसा इसलिए होगा, क्योंकि उपयोगकर्ता को लॉन्चर के कोल्ड स्टार्ट होने का इंतज़ार करना होगा.
  • इनपुट पद्धति संपादक (IME): टाइपिंग करते समय, सिस्टम आपके चुने गए कीबोर्ड ऐप्लिकेशन (जैसे, Gboard) से जुड़ जाता है. इससे कीबोर्ड की प्रोसेस को बेहतर स्थिति में रखा जाता है. भले ही, कीबोर्ड को कुछ समय के लिए छिपा दिया गया हो. इससे यह पक्का होता है कि किसी दूसरे टेक्स्ट फ़ील्ड पर टैप करने पर, कीबोर्ड तुरंत फिर से दिख जाए.
  • एनएफ़सी पेमेंट: पेमेंट करने के लिए फ़ोन को टैप करने पर, सिस्टम एनएफ़सी पेमेंट सेवा (जैसे, Google Wallet) से जुड़ जाता है. इन लेन-देन के लिए, कारोबारी या कंपनी के टर्मिनल से रीयल-टाइम में पुष्टि करना ज़रूरी होता है. अगर पेमेंट ऐप्लिकेशन को कोल्ड स्टार्ट करना पड़ा, तो लेन-देन का समय खत्म हो सकता है और वह पूरा नहीं हो सकता.

ट्रेडऑफ़ और परफ़ॉर्मेंस में अचानक गिरावट

बाइंडिंग, परफ़ॉर्मेंस और सही तरीके से काम करने के लिए ज़रूरी हैं. हालांकि, इससे सिस्टम की मेमोरी पर असर पड़ता है.

  • कम फ़्लेक्सिबिलिटी: हर बाउंड प्रोसेस एक ऐसी प्रोसेस होती है जिसे एलएमके आसानी से बंद नहीं कर सकता. इससे, कैश मेमोरी में सेव की गई प्रोसेस का "कुशन" कम हो जाता है. इसका इस्तेमाल सिस्टम, मेमोरी को खाली करने के लिए कर सकता है.
  • परफ़ॉर्मेंस में गिरावट: अगर बहुत सारी प्रोसेस बाउंड हैं, तो सिस्टम को ऐसी बैकग्राउंड प्रोसेस नहीं मिल सकती जिन्हें बंद किया जा सके. मेमोरी पर दबाव बढ़ने पर, सिस्टम की परफ़ॉर्मेंस बहुत तेज़ी से खराब हो जाएगी. ऐसा इसलिए, क्योंकि सिस्टम को ज़्यादा ज़रूरी प्रोसेस बंद करनी होंगी या पेज कैश को मिटाना होगा.

← शहर | ↑ ऊपर जाएं | सिस्टम-वाइड →