يهدف نظام تسجيل الأحداث في Android إلى تحقيق إمكانية الوصول الشاملة وسهولة الاستخدام، على افتراض أنّه يمكن تمثيل جميع بيانات السجلّ كسلسلة من الأحرف. يتوافق هذا الافتراض مع معظم حالات الاستخدام، لا سيما عندما تكون قراءة السجلّ أمرًا بالغ الأهمية بدون استخدام أدوات متخصّصة. ومع ذلك، في البيئات التي تتطلّب أداءً عاليًا لتسجيل الأحداث وأحجام سجلّات محدودة، لا يكون تسجيل الأحداث المستند إلى النصوص هو الخيار الأمثل. أحد هذه السيناريوهات هو WindowManager، الذي يتطلّب نظام تسجيل أحداث قويًا يعالج سجلّات نقل النوافذ في الوقت الفعلي بأقل تأثير على النظام.
ProtoLog هو البديل الذي يلبي احتياجات تسجيل الأحداث في WindowManager والخدمات المماثلة. يقدّم ProtoLog المزايا التالية مقارنةً بـ logcat:
- يستخدم موارد أقل لتسجيل الأحداث.
- من منظور المطوّر، يعمل بالطريقة نفسها التي يعمل بها إطار تسجيل الأحداث التلقائي في Android.
- يتيح لك تفعيل عبارات السجلّ أو إيقافها في وقت التشغيل.
- يمكنه أيضًا تسجيل الأحداث في logcat.
لتحسين استخدام الذاكرة، يستخدم ProtoLog آلية لتخزين السلاسل. تحسب هذه الآلية وتخزّن قيمة تجزئة مجمّعة للرسالة. لتحسين الأداء، يُجري ProtoLog عملية تخزين السلاسل أثناء التجميع لخدمات النظام. ولا يسجّل سوى معرّف الرسالة والوسيطات في وقت التشغيل. عند إنشاء تتبُّع ProtoLog أو الحصول على تقرير عن الأخطاء، يدمج ProtoLog تلقائيًا قاموس الرسائل الذي تم إنشاؤه في وقت التجميع. يتيح ذلك فك تشفير الرسائل من أي إصدار.
يخزّن ProtoLog الرسائل بتنسيق ثنائي (proto) ضمن تتبُّع Perfetto.
يتم فك تشفير الرسائل ضمن trace_processor في Perfetto. تفك العملية تشفير رسائل proto الثنائية، وتترجم معرّفات الرسائل إلى سلاسل باستخدام قاموس الرسائل المضمّن، وتنسّق السلسلة باستخدام وسيطات ديناميكية.
يوفّر ProtoLog مستويات السجلّ نفسها التي يوفّرها android.utils.Log، وهي d و
v وi وw وe وwtf.
ProtoLog من جهة العميل
في البداية، كان من المفترض استخدام ProtoLog فقط من جهة الخادم في WindowManager، حيث يعمل ضمن عملية ومكوّن واحدَين. لاحقًا، تم توسيعه ليشمل رمز shell في WindowManager في عملية واجهة مستخدم النظام. ومع ذلك، كان استخدام ProtoLog يتطلّب رمز إعداد معقدًا. بالإضافة إلى ذلك، كان تسجيل الأحداث في ProtoLog مقتصرًا على خادم النظام وعمليات واجهة مستخدم النظام. وقد صعّب ذلك دمجه في عمليات أخرى وتطلّب إعداد مخزن مؤقت منفصل للذاكرة لكل عملية. يتوفّر ProtoLog الآن للرمز من جهة العميل، ما يزيل الحاجة إلى رمز النص النموذجي الإضافي.
على عكس رمز خدمات النظام، يتخطّى الرمز من جهة العميل عادةً عملية تخزين السلاسل في وقت التجميع. بدلاً من ذلك، يتم تخزين السلاسل ديناميكيًا في سلسلة محادثات في الخلفية. نتيجةً لذلك، على الرغم من أنّ ProtoLog من جهة العميل يقدّم مزايا في استخدام الذاكرة قابلة للمقارنة مع ProtoLog في خدمات النظام، فإنّه يتكبّد تكلفة إضافية أعلى قليلاً على الأداء ولا يقدّم ميزة تقليل الذاكرة للذاكرة المثبّتة التي يقدّمها نظيره من جهة الخادم.
مجموعات ProtoLog
يتم تنظيم رسائل ProtoLog في مجموعات تُسمّى ProtoLogGroups، على غرار
طريقة تنظيم رسائل Logcat حسب TAG. تعمل ProtoLogGroups كمجموعات من الرسائل يمكنك تفعيلها أو إيقافها في وقت التشغيل. تتحكّم أيضًا في ما إذا كانت الرسائل يتم حذفها أثناء التجميع ومكان تسجيلها
(proto أو logcat أو كليهما). يتضمّن كل ProtoLogGroup الخصائص التالية:
enabled: عند ضبطها علىfalse، يتم استبعاد الرسائل في هذه المجموعة أثناء التجميع ولا تكون متاحة في وقت التشغيل.logToProto: تحدّد ما إذا كانت هذه المجموعة تسجّل الأحداث بتنسيق ثنائي.logToLogcat: تحدّد ما إذا كانت هذه المجموعة تسجّل الأحداث في logcat.tag: اسم مصدر الرسالة المسجّلة.
يجب أن يكون لكل عملية تستخدم ProtoLog مثيل ProtoLogGroup تم إعداده.
أنواع الوسيطات المتوافقة
يُنسّق ProtoLog السلاسل داخليًا باستخدام android.text.TextUtils#formatSimple(String, Object...),
لذا يكون البناء هو نفسه.
يوفّر ProtoLog أنواع الوسيطات التالية:
%b- قيمة منطقية%d،%x- نوع عدد صحيح (قصير أو صحيح أو طويل)%f- نوع عدد عشري (float أو double)%s- سلسلة%%- حرف النسبة المئوية
يتم دعم معدِّلات العرض والدقة، مثل %04d و%10b.
ومع ذلك، لا يتم دعم argument_index وflags.
استخدام ProtoLog في خدمة جديدة
لاستخدام ProtoLog في خدمة جديدة، اتّبِع الخطوات التالية:
- أنشئ تعريفًا لـ
ProtoLogGroupلهذه الخدمة. هيِّئ التعريف قبل استخدامه لأول مرة. على سبيل المثال، هيِّئه أثناء إنشاء العملية:
ProtoLog.init(ProtoLogGroup.values());استخدِم
ProtoLogبالطريقة نفسها التي تستخدم بهاandroid.util.Log:ProtoLog.v(WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId);
تفعيل التحسين في وقت التجميع
لتفعيل ProtoLog في وقت التجميع في إحدى العمليات، عليك تغيير قواعد الإصدار واستدعاء الملف الثنائي protologtool.
ProtoLogTool هو ملف ثنائي لتحويل الرموز البرمجية يُجري عملية تخزين السلاسل ويعدّل استدعاء ProtoLog. يحوّل هذا البرنامج الثنائي كل استدعاء لتسجيل الأحداث في ProtoLog كما هو موضّح في هذا المثال:
ProtoLog.x(ProtoLogGroup.GROUP_NAME, "Format string %d %s", value1, value2);
إلى:
if (ProtoLogImpl.isEnabled(GROUP_NAME)) {
int protoLogParam0 = value1;
String protoLogParam1 = String.valueOf(value2);
ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 1234560b0100, protoLogParam0, protoLogParam1);
}
في هذا المثال، ProtoLog وProtoLogImpl وProtoLogGroup هي الفئات المقدَّمة كوسيطات (يمكن استيرادها أو استيرادها بشكل ثابت أو استخدام المسار الكامل لها، ولا يُسمح بعمليات الاستيراد باستخدام أحرف البدل)، وx هي طريقة تسجيل الأحداث.
يتم التحويل على مستوى المصدر. يتم إنشاء قيمة تجزئة من سلسلة التنسيق ومستوى السجلّ واسم مجموعة السجلّ، ويتم إدراجها بعد وسيطة ProtoLogGroup. يتم تضمين الرمز الذي تم إنشاؤه فعليًا ويتم إضافة عدد من أحرف السطر الجديد للحفاظ على ترقيم الأسطر في الملف.
مثال:
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"],
}
خيارات سطر الأوامر
إحدى المزايا الرئيسية لـ ProtoLog هي أنّه يمكنك تفعيله أو إيقافه في وقت التشغيل. على سبيل المثال، يمكنك تسجيل الأحداث بشكل أكثر تفصيلاً في إصدار، مع إيقاف هذه الميزة تلقائيًا، ثم تفعيلها أثناء التطوير المحلي لتصحيح خطأ معيّن. يتم استخدام هذا النمط، على سبيل المثال، في WindowManager مع المجموعتَين
WM_DEBUG_WINDOW_TRANSITIONS و WM_DEBUG_WINDOW_TRANSITIONS_MIN لتفعيل
أنواع مختلفة من تسجيل أحداث النقل، مع تفعيل المجموعة الأولى تلقائيًا.
يمكنك إعداد ProtoLog باستخدام Perfetto عند بدء تتبُّع. يمكنك أيضًا
إعداد ProtoLog محليًا باستخدام سطر أوامر adb.
يسمح الأمر adb shell cmd protolog_configuration باستخدام الوسيطات التالية:
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
نصائح للاستخدام الفعّال
يستخدم ProtoLog عملية تخزين السلاسل لكل من الرسالة وأي وسيطات سلسلة يتم تمريرها. يعني ذلك أنّه للاستفادة بشكل أكبر من ProtoLog، يجب أن تفصل الرسائل القيم المتكرّرة في متغيرات.
على سبيل المثال، لنفترض العبارة التالية:
Protolog.v(MY_GROUP, "%s", "The argument value is " + argument);
عند تحسينها في وقت التجميع، تتم ترجمتها إلى ما يلي:
ProtologImpl.v(MY_GROUP, 0x123, "The argument value is " + argument);
إذا تم استخدام ProtoLog في الرمز مع الوسيطات A,B,C:
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");
سيؤدي ذلك إلى ظهور الرسائل التالية في الذاكرة:
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)
إذا تمت كتابة عبارة ProtoLog بدلاً من ذلك على النحو التالي:
Protolog.v(MY_GROUP, "The argument value is %s", argument);
سينتهي الأمر بالمخزن المؤقت في الذاكرة على النحو التالي:
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)
تؤدي هذه السلسلة إلى استخدام ذاكرة أصغر بنسبة% 35.
عارض Winscope
تعرض علامة التبويب "عارض ProtoLog" في Winscope عمليات تتبُّع ProtoLog منظَّمة بتنسيق جدولي. يمكنك فلترة عمليات التتبُّع حسب مستوى السجلّ والعلامة وملف المصدر (الذي تتضمّن عبارة ProtoLog) ومحتوى الرسالة. يمكن فلترة جميع الأعمدة. يؤدي النقر على الطابع الزمني في العمود الأول إلى نقل المخطط الزمني إلى الطابع الزمني للرسالة. بالإضافة إلى ذلك، يؤدي النقر على الانتقال إلى الوقت الحالي إلى إعادة تمرير جدول ProtoLog إلى الطابع الزمني الذي تم اختياره في المخطط الزمني:
الشكل 1: عارض ProtoLog