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:
Bu hizmet için bir
ProtoLogGroup
tanım oluşturun.Tanımı ilk kullanımdan önce başlatın (örneğin, işlem oluşturma sırasında):
Protolog.init(ProtologGroup.values());
Protolog
öğesiniandroid.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:
1. şekil. ProtoLog görüntüleyici