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 günlük okunabilirliğinin özel araçlar olmadan çok önemli olduğu durumlarda çoğu kullanım alanıyla uyumludur. Ancak yüksek günlük kaydı performansı ve kısıtlanmış günlük boyutları gerektiren ortamlarda metin tabanlı günlük kaydı ideal değildir. Bu tür senaryolardan biri, gerçek zamanlı pencere geçiş günlüklerini minimum sistem etkisiyle işleyen sağlam bir günlük kaydı sistemi gerektiren WindowManager'dır.
ProtoLog, WindowManager ve benzer hizmetlerin günlük kaydı ihtiyaçlarını karşılamak için kullanılan alternatif bir yöntemdir. ProtoLog, logcat'e kıyasla aşağıdaki avantajları sunar:
- Günlüğe kaydetme için daha az kaynak kullanır.
- Geliştirici açısından bakıldığında, varsayılan Android günlük kaydı çerçevesiyle aynı şekilde çalışır.
- Günlük ifadelerini çalışma zamanında etkinleştirmenize veya devre dışı bırakmanıza olanak tanır.
- Logcat'e de kaydedilebilir.
ProtoLog, bellek kullanımını optimize etmek için dize yerleştirme mekanizması kullanır. Bu mekanizma, iletinin derlenmiş bir karma değerini hesaplayıp kaydeder. ProtoLog, performansı artırmak için sistem hizmetleri derlenirken dize intern işlemi gerçekleştirir. Yalnızca ileti tanımlayıcısını ve bağımsız değişkenleri çalışma zamanında kaydeder. ProtoLog izlemesi oluşturduğunuzda veya hata raporu aldığınızda ProtoLog, derleme zamanında oluşturulan mesaj sözlüğünü otomatik olarak dahil eder. Bu seçenek, herhangi bir derlemeden mesaj kod çözme işlemini etkinleştirir.
ProtoLog, iletileri Perfetto izinde ikili biçimde (proto) depolar.
İleti kod çözme işlemi Perfetto'nun trace_processor içinde gerçekleşir. Bu işlem, ikili proto mesajlarının kodunu çözer, yerleştirilmiş mesaj sözlüğünü kullanarak mesaj tanımlayıcılarını dizelere çevirir ve dizeyi dinamik bağımsız değişkenlerle biçimlendirir.
ProtoLog, android.utils.Log ile aynı günlük seviyelerini (d, v, i, w, e ve wtf) destekler.
İ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, System UI sürecindeki WindowManager kabuk kodunu kapsayacak şekilde genişletildi. Ancak ProtoLog'un kullanılması için karmaşık bir standart kurulum kodu gerekiyordu. Ayrıca, Proto günlük kaydı sistem sunucusu ve Sistem Arayüzü işlemleriyle sınırlandırıldı. Bu durum, diğer süreçlere dahil etmeyi zorlaştırıyor ve her biri için ayrı bir bellek arabelleği kurulumu gerektiriyordu. ProtoLog artık istemci tarafı kodunda kullanılabiliyor ve ek standart kod ihtiyacını ortadan kaldırıyor.
Sistem hizmetleri kodunun aksine, istemci tarafı kodu genellikle derleme zamanı dize intern işlemini atlar. Bunun yerine, dize yerleştirme işlemi arka plan iş parçacığında dinamik olarak gerçekleşir. Sonuç olarak, istemci tarafı ProtoLog, sistem hizmetlerindeki ProtoLog'a benzer bellek kullanımı avantajları sunsa da biraz daha yüksek bir performans ek yüküne neden olur ve sunucu tarafı karşılığının sunduğu sabitlenmiş bellek avantajına sahip değildir.
ProtoLog grupları
ProtoLog mesajları, Logcat mesajlarının TAG'ye göre düzenlenmesine benzer şekilde ProtoLogGroups adı verilen gruplar halinde düzenlenir. Bunlar, ProtoLogGroups çalışma zamanında etkinleştirebileceğiniz veya devre dışı bırakabileceğiniz ileti kümeleri olarak işlev görür. Ayrıca, derleme sırasında mesajların temizlenip temizlenmeyeceğini ve nereye kaydedileceğini (proto, logcat veya her ikisi) de kontrol ederler. Her ProtoLogGroup aşağıdaki özellikleri içerir:
enabled:falseolarak 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
ProtoLog, dizeleri dahili olarak android.text.TextUtils#formatSimple(String, Object...) kullanarak biçimlendirdiğinden 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 hassasiyet değiştiriciler desteklenir.
Ancak argument_index ve flags desteklenmez.
Yeni bir hizmette ProtoLog'u kullanma
ProtoLog'u yeni bir hizmette kullanmak için aşağıdaki adımları uygulayın:
- Bu hizmet için bir
ProtoLogGrouptanım oluşturun. Tanımı ilk kullanımdan önce başlatın. Örneğin, işlem oluşturma sırasında başlatın:
ProtoLog.init(ProtoLogGroup.values());ProtoLogöğesiniandroid.util.Logöğesini kullandığınız ş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 ikilisidir. 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 karakterle içe aktarmaya 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 sorunu ayıklamak için yerel geliştirme sırasında etkinleştirilen daha ayrıntılı günlük kaydı olabilir. Bu kalıp, örneğin WindowManager'da kullanılır. WM_DEBUG_WINDOW_TRANSITIONS ve WM_DEBUG_WINDOW_TRANSITIONS_MIN 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:
Şekil 1. ProtoLog görüntüleyici