ProtoGünlük

Android günlük kaydı sistemi, tüm günlük verilerinin bir karakter dizisi olarak temsil edilebileceği varsayılarak 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 çoğu kullanım alanı için geçerlidir. Ancak, yüksek günlük kaydı performansı ve kısıtlanmış günlük boyutları gerektiren ortamlarda metne dayalı günlük kaydı en uygun seçenek olmayabilir. Bu tür senaryolardan biri olan WindowManager, gerçek zamanlı pencere geçiş günlüklerini minimum sistem etkisiyle işleyebilecek güçlü bir günlük kaydı sistemi gerektirir.

ProtoLog, WindowManager ve benzer hizmetlerin günlük kaydı ihtiyaçlarını karşılamak için kullanılan alternatiftir. ProtoLog'un logcat'e kıyasla başlıca avantajları şunlardır:

  • Günlüğe kaydetme için kullanılan kaynak miktarı daha azdır.
  • Geliştirici açısından, 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 günlük kaydı almaya devam edebilir.

ProtoLog, bellek kullanımını optimize etmek için mesajın derlenmiş karmasını hesaplayıp kaydetmeyi içeren bir dize içe aktarma mekanizması kullanır. ProtoLog, performansı artırmak için derleme sırasında (sistem hizmetleri için) dize içe aktarma işlemi gerçekleştirir ve yalnızca çalışma zamanında mesaj tanımlayıcısını ve bağımsız değişkenleri kaydeder. Ayrıca ProtoLog, bir ProtoLog izlemesi oluştururken veya hata raporu alırken derleme sırasında oluşturulan mesaj sözlüğünü otomatik olarak dahil eder. Bu sayede, herhangi bir derlemedeki mesajların kodunu çözebilirsiniz.

ProtoLog kullanılarak mesaj, bir Perfetto izlemesinde ikili biçimde (proto) saklanır. İleti kod çözme işlemi, Perfetto'nun trace_processor içinde gerçekleşir. Bu işlem, ikili proto mesajların kodunu çözme, mesaj tanımlayıcılarını yerleşik mesaj sözlüğünü kullanarak dizelere çevirme ve dize biçimlendirmeyi dinamik bağımsız değişkenler kullanarak gerçekleştirme işlemlerinden oluşur.

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

İstemci tarafı ProtoLog

ProtoLog başlangıçta yalnızca tek bir işlem ve bileşen içinde çalışan WindowManager'ın sunucu tarafı için tasarlanmıştı. Daha sonra, Sistem Kullanıcı Arayüzü işlemindeki WindowManager kabuk kodunu kapsayacak şekilde genişletildi ancak ProtoLog kullanımı için karmaşık bir şablon kurulum kodu gerekiyordu. Ayrıca, Proto günlük kaydı sistem sunucusu ve sistem kullanıcı arayüzü işlemleriyle sınırlıydı. Bu da diğer işlemlere dahil edilmesini zorlaştırıyor ve her biri için ayrı bir bellek arabelleği kurulumu gerektiriyordu. Ancak ProtoLog artık istemci tarafı kod için kullanıma sunuldu. Bu sayede ek şablon kod ihtiyacı ortadan kalktı.

Sistem hizmetleri kodunun aksine istemci tarafı kodunda genellikle derleme zamanı dize içe aktarma atlanır. Bunun yerine, dize içe aktarma işlemi arka plandaki bir mesaj dizisinde dinamik olarak gerçekleşir. Sonuç olarak, istemci tarafındaki ProtoLog, sistem hizmetlerindeki ProtoLog'a benzer bellek kullanımı avantajları sağlarken performans açısından biraz daha fazla yük oluşturur ve sunucuda çalışan muadilinin sabitlenmiş bellek avantajından yoksundur.

ProtoLog grupları

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

  • enabled: false olarak ayarlandığında, bu gruptaki iletiler derleme sırasında hariç tutulur ve çalışma zamanında kullanılamaz.
  • logToProto: Bu grubun günlükleri ikili biçimde kaydedip kaydetmediğini tanımlar.
  • logToLogcat: Bu grubun logcat'e günlük kaydedip kaydetmeyeceğini tanımlar.
  • tag: Günlüğe kaydedilen mesajın kaynağının adı.

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

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

ProtoLog, dahili olarak android.text.TextUtils#formatSimple(String, Object...) kullanarak dizeleri biçimlendirir. Bu nedenle söz dizimi aynıdır.

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

  • %b - boole
  • %d, %x: tam sayı türü (short, integer veya long)
  • %f - kayan nokta türü (float veya double)
  • %s - dize
  • %%: Yüzde karakteri

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

ProtoLog'u yeni bir hizmette 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ımından önce başlatın (örneğin, işlem oluşturulurken):

    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 içe aktarma 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);

hedef:

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) ve x günlük kaydı yöntemidir.

Dönüşüm, kaynak düzeyinde yapılır. Format dizesi, günlük düzeyi ve günlük grubu adından bir karma oluşturulur ve ProtoLogGroup bağımsız değişkeninin ardından eklenir. Oluşturulan gerçek kod satır içine yerleştirilir ve dosyada 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 en önemli avantajlarından biri, çalışma zamanında etkinleştirilebilmesi veya devre dışı bırakılabilmesidir. Örneğin, varsayılan olarak devre dışı bırakılan bir derlemede daha ayrıntılı günlük kaydı alabilir ve belirli bir sorunla ilgili hata ayıklama için yerel geliştirme sırasında bu özelliği etkinleştirebilirsiniz. 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ı geçiş günlüğü türlerini etkinleştirir. Bunlardan ilki varsayılan olarak etkindir.

Bir izlemeyi başlatırken Perfetto'yu kullanarak ProtoLog'u 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 tüm dize bağımsız değişkenleri için dize içe aktarma işlemi kullanır. Bu, ProtoLog'dan daha fazla yararlanmak için mesajların tekrarlanan değerleri değişkenler halinde ayırması gerektiği anlamına gelir.

Ö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);

Kodda ProtoLog, 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 mesajların gösterilmesine 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ış olsaydı:

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

Bellekteki arabellek şu şekilde olur:

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 izine neden olur.

Winscope görüntüleyici

Winscope'un ProtoLog görüntüleyici sekmesi, ProtoLog izlerini tablo biçiminde düzenler. İzlemeleri günlük düzeyine, etikete, kaynak dosyaya (ProtoLog ifadesinin bulunduğu yer) ve mesaj 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 taşınır. Ayrıca, Mevcut Zamana Git'i tıkladığınızda ProtoLog tablosu zaman çizelgesinde seçilen zaman damgasına geri döner:

ProtoLog görüntüleyici

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