ProtoGünlük

Android günlük kaydı sistemi, tüm günlük verilerinin bir karakter dizisi olarak gösterilebileceği varsayımıyla evrensel erişilebilirlik ve kullanım kolaylığı sağlamayı amaçlar. Bu varsayım, özellikle özel araçlar olmadan günlük okunabilirliğinin önemli olduğu durumlarda çoğu kullanım alanıyla uyumludur. Ancak yüksek günlük kaydı performansı ve sınırlı günlük boyutu gerektiren ortamlarda metin tabanlı günlük kaydı ideal olmayabilir. Bu tür senaryolardan biri, WindowManager'dır. Bu senaryo, sistem üzerinde minimum etkiyle gerçek zamanlı pencere geçişi günlüklerini işleyebilen güçlü bir günlük kaydı sistemini gerektirir.

ProtoLog, WindowManager ve benzer hizmetlerin günlük kaydı ihtiyaçlarını karşılamak için kullanılan alternatif bir yöntemdir. ProtoLog'un logcat'e kıyasla temel avantajları şunlardır:

  • Günlüğe kaydetme için kullanılan kaynak miktarı daha azdır.
  • Geliştirici açısından bu, varsayılan Android günlük kaydı çerçevesini kullanmakla aynıdır.
  • Günlük ifadelerinin çalışma zamanında etkinleştirilmesini veya devre dışı bırakılmasını destekler.
  • Gerekirse logcat'e kaydetmeye devam edebilirsiniz.

ProtoLog, bellek kullanımını optimize etmek için ileti derlenmiş karmasını hesaplamayı ve kaydetmeyi içeren bir dize dahili mekanizması kullanır. ProtoLog, performansı artırmak için derleme sırasında (sistem hizmetleri için) dize yerleştirme işlemi gerçekleştirir ve yalnızca mesaj tanımlayıcı ile bağımsız değişkenleri çalışma zamanında kaydeder. Ayrıca, ProtoLog izi oluştururken veya hata raporu alırken ProtoLog, derleme sırasında oluşturulan mesaj sözlüğünü otomatik olarak dahil ederek herhangi bir derlemeden mesaj kod çözme işlemini etkinleştirir.

ProtoLog kullanıldığında mesaj, Perfetto izinde ikili biçimde (proto) saklanır. İleti kod çözme işlemi Perfetto'nun trace_processor içinde gerçekleşir. Bu süreçte, ikili proto iletilerin kodu çözülür, ileti tanımlayıcıları yerleştirilmiş ileti sözlüğünü kullanarak dizelere çevrilir ve dize dinamik bağımsız değişkenler kullanılarak biçimlendirilir.

ProtoLog, android.utils.Log ile aynı günlük seviyelerini destekler. Bunlar: d, v, i, w, e, wtf.

İstemci tarafı ProtoLog

Başlangıçta ProtoLog, tek bir işlem ve bileşen içinde çalışan WindowManager'ın yalnızca sunucu tarafı için tasarlanmıştı. Daha sonra, System UI sürecindeki WindowManager kabuk kodunu kapsayacak şekilde genişletildi ancak ProtoLog kullanımı için karmaşık bir standart kurulum kodu gerekiyordu. Ayrıca, Proto günlük kaydı sistem sunucusu ve Sistem Kullanıcı Arayüzü süreçleriyle sınırlıydı. Bu nedenle, diğer süreçlere dahil edilmesi zorlaşıyor ve her biri için ayrı bir bellek arabelleği kurulumu gerekiyordu. Ancak ProtoLog artık istemci tarafı kodunda kullanılabiliyor ve ek standart kod ihtiyacını ortadan kaldırıyor.

İstemci tarafı kodu, sistem hizmetleri kodunun aksine genellikle derleme zamanı dize yerleştirmeyi atlar. Bunun yerine, dize dahilileştirme işlemi arka plan iş parçacığında dinamik olarak gerçekleşir. Sonuç olarak, istemci tarafındaki ProtoLog, sistem hizmetlerindeki ProtoLog'a benzer bellek kullanımı avantajları sunsa da biraz daha yüksek performans ek yüküne neden olur ve sunucu tarafındaki karşılığının sabitlenmiş bellek avantajına sahip değildir.

ProtoLog grupları

ProtoLog mesajları, Logcat mesajlarının TAG tarafından düzenlenmesine benzer şekilde ProtoLogGroups adı verilen gruplar halinde düzenlenir. Bu ProtoLogGroups, çalışma zamanında toplu olarak etkinleştirilebilen veya devre dışı bırakılabilen mesaj kümeleri olarak işlev görür. Ayrıca, derleme sırasında iletilerin kaldırılıp kaldırılmayacağını ve nereye kaydedileceğini (proto, logcat veya her ikisi) kontrol ederler. Her ProtoLogGroup aşağıdaki özelliklerden oluşur:

  • enabled: false olarak ayarlandığında, bu gruptaki iletiler derleme sırasında hariç tutulur ve çalışma zamanında kullanılamaz.
  • logToProto: Bu grubun ikili biçimde günlük kaydı oluşturup oluşturmayacağını tanımlar.
  • logToLogcat: Bu grubun logcat'e kaydedilip kaydedilmeyeceğini tanımlar.
  • tag: Kaydedilen iletinin kaynağının adı.

ProtoLog'u kullanan her işlemin yapılandırılmış bir ProtoLogGroup örneği olmalıdır.

Desteklenen bağımsız değişken türleri

Dahili olarak ProtoLog biçim dizeleri android.text.TextUtils#formatSimple(String, Object...) kullandığından söz dizimi aynıdır.

ProtoLog aşağıdaki bağımsız değişken türlerini destekler:

  • %b - boolean
  • %d, %x - integral türü (short, integer veya long)
  • %f - kayan nokta türü (float veya double)
  • %s - dize
  • %%: değişmez yüzde işareti

%04d ve %10b gibi genişlik ve duyarlık değiştiriciler desteklenir ancak argument_index ve flags desteklenmez.

Yeni bir hizmette ProtoLog'u kullanma

ProtoLog'u yeni bir süreçte kullanmak için:

  1. Bu hizmet için bir ProtoLogGroup tanım oluşturun.

  2. Tanımı ilk kullanımdan önce başlatın (örneğin, işlem oluşturma sırasında):

    Protolog.init(ProtologGroup.values());

  3. Protolog öğesini android.util.Log ile aynı şekilde kullanın:

    ProtoLog.v(WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId);

Derleme zamanı optimizasyonunu etkinleştirme

Bir süreçte derleme zamanı ProtoLog'u etkinleştirmek için derleme kurallarını değiştirmeniz ve protologtool ikili programını çağırmanız gerekir.

ProtoLogTool, dize yerleştirme işlemi gerçekleştiren ve ProtoLog çağrısını güncelleyen bir kod dönüştürme ikili programıdır. Bu ikili, her ProtoLog günlük kaydı çağrısını aşağıdaki örnekte gösterildiği gibi dönüştürür:

ProtoLog.x(ProtoLogGroup.GROUP_NAME, "Format string %d %s", value1, value2);

şununla:

if (ProtoLogImpl.isEnabled(GROUP_NAME)) {
    int protoLogParam0 = value1;
    String protoLogParam1 = String.valueOf(value2);
    ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 1234560b0100, protoLogParam0, protoLogParam1);
}

Bu örnekte, ProtoLog, ProtoLogImpl ve ProtoLogGroup, bağımsız değişken olarak sağlanan sınıflardır (içe aktarılabilir, statik olarak içe aktarılabilir veya tam yol olabilir, joker karakter içe aktarmalarına izin verilmez). x ise günlük kaydı yöntemidir.

Dönüştürme işlemi kaynak düzeyinde yapılır. Karma, biçim dizesi, günlük düzeyi ve günlük grubu adından oluşturulur ve ProtoLogGroup bağımsız değişkeninden sonra eklenir. Gerçek oluşturulan kod satır içi olarak eklenir ve satır numaralandırmasını korumak için bir dizi yeni satır karakteri eklenir.

Örnek:

genrule {
    name: "wm_shell_protolog_src",
    srcs: [
        ":protolog-impl", // protolog lib
        ":wm_shell_protolog-groups", // protolog groups declaration
        ":wm_shell-sources", // source code
    ],
    tools: ["protologtool"],
    cmd: "$(location protologtool) transform-protolog-calls " +
        "--protolog-class com.android.internal.protolog.ProtoLog " +
        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
        "--loggroups-jar $(location :wm_shell_protolog-groups) " +
        "--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " +
        "--legacy-viewer-config-file-path /system_ext/etc/wmshell.protolog.json.gz " +
        "--legacy-output-file-path /data/misc/wmtrace/shell_log.winscope " +
        "--output-srcjar $(out) " +
        "$(locations :wm_shell-sources)",
    out: ["wm_shell_protolog.srcjar"],
}

Komut satırı seçenekleri

ProtoLog'un temel avantajlarından biri, çalışma zamanında etkinleştirilip devre dışı bırakılabilmesidir. Örneğin, bir derlemede varsayılan olarak devre dışı bırakılan ve belirli bir sorunda hata ayıklamak için yerel geliştirme sırasında etkinleştirilen daha ayrıntılı günlük kaydı oluşturabilirsiniz. Bu kalıp, örneğin WindowManager'da WM_DEBUG_WINDOW_TRANSITIONS ve WM_DEBUG_WINDOW_TRANSITIONS_MIN gruplarıyla birlikte kullanılır. Bu gruplar, farklı türlerde geçiş günlüğü kaydını etkinleştirir. İlk grup varsayılan olarak etkindir.

İzlemeyi başlatırken ProtoLog'u Perfetto'yu kullanarak yapılandırabilirsiniz. ProtoLog'u adb komut satırını kullanarak yerel olarak da yapılandırabilirsiniz.

adb shell cmd protolog_configuration komutu aşağıdaki bağımsız değişkenleri destekler:

help
  Print this help text.

groups (list | status)
  list - lists all ProtoLog groups registered with ProtoLog service"
  status <group> - print the status of a ProtoLog group"

logcat (enable | disable) <group>"
  enable or disable ProtoLog to logcat

Etkili kullanım için ipuçları

ProtoLog, hem ileti hem de iletilen dize bağımsız değişkenleri için dize yerleştirme kullanır. Bu nedenle, ProtoLog'dan daha fazla yararlanmak için mesajlar, tekrarlanan değerleri değişkenlere ayırmalıdır.

Örneğin, aşağıdaki ifadeyi ele alalım:

Protolog.v(MY_GROUP, "%s", "The argument value is " + argument);

Derleme zamanında optimize edildiğinde şu şekilde çevrilir:

ProtologImpl.v(MY_GROUP, 0x123, "The argument value is " + argument);

ProtoLog, kodda A,B,C bağımsız değişkenleriyle kullanılıyorsa:

Protolog.v(MY_GROUP, "%s", "The argument value is A");
Protolog.v(MY_GROUP, "%s", "The argument value is B");
Protolog.v(MY_GROUP, "%s", "The argument value is C");
Protolog.v(MY_GROUP, "%s", "The argument value is A");

Bu işlem, bellekte aşağıdaki iletilerin oluşmasına neden olur:

Dict:
  0x123: "%s"
  0x111: "The argument value is A"
  0x222: "The argument value is B"
  0x333: "The argument value is C"

Message1 (Hash: 0x123, Arg1: 0x111)
Message2 (Hash: 0x123, Arg2: 0x222)
Message3 (Hash: 0x123, Arg3: 0x333)
Message4 (Hash: 0x123, Arg1: 0x111)

Bunun yerine ProtoLog ifadesi şu şekilde yazılmışsa:

Protolog.v(MY_GROUP, "The argument value is %s", argument);

Bellekteki arabellek şu şekilde sonuçlanır:

Dict:
  0x123: "The argument value is %s" (24 b)
  0x111: "A" (1 b)
  0x222: "B" (1 b)
  0x333: "C" (1 b)

Message1 (Hash: 0x123, Arg1: 0x111)
Message2 (Hash: 0x123, Arg2: 0x222)
Message3 (Hash: 0x123, Arg3: 0x333)
Message4 (Hash: 0x123, Arg1: 0x111)

Bu sıra, %35 daha küçük bir bellek ayak iziyle sonuçlanır.

Winscope görüntüleyici

Winscope'un ProtoLog görüntüleyici sekmesinde, tablo biçiminde düzenlenmiş ProtoLog izleri gösterilir. İzleri günlük düzeyine, etikete, kaynak dosyaya (ProtoLog ifadesinin bulunduğu yer) ve ileti içeriğine göre filtreleyebilirsiniz. Tüm sütunlar filtrelenebilir. İlk sütundaki zaman damgasını tıkladığınızda zaman çizelgesi, mesajın zaman damgasına yönlendirilir. Ayrıca, Geçerli Zamana Git'i tıkladığınızda ProtoLog tablosu, zaman çizelgesinde seçilen zaman damgasına geri kaydırılır:

ProtoLog görüntüleyici

1. şekil. ProtoLog görüntüleyici