Merge "Remove the deprecated StatsdDogfood and LoadTest app."

This commit is contained in:
TreeHugger Robot
2019-07-24 00:37:47 +00:00
committed by Android (Google) Code Review
37 changed files with 0 additions and 3622 deletions

View File

@@ -1,37 +0,0 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
android_app {
name: "StatsdDogfood",
platform_apis: true,
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
static_libs: [
"platformprotoslite",
"statsdprotolite",
],
privileged: true,
dex_preopt: {
enabled: false,
},
certificate: "platform",
optimize: {
enabled: false,
},
}

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.statsd.dogfood"
android:sharedUserId="android.uid.system"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.DUMP" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MainActivity$ReceiverIntentService" android:exported="true" />
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,162 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/push_config"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_green_light"
android:text="@string/push_config"/>
<Button
android:id="@+id/set_receiver"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_green_light"
android:text="@string/set_receiver"/>
<Button
android:id="@+id/remove_receiver"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_green_light"
android:text="@string/remove_receiver"/>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/app_a_wake_lock_acquire1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_a_get_wl1"/>
<Button android:id="@+id/app_a_wake_lock_release1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_a_release_wl1"/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/app_a_wake_lock_acquire2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_a_get_wl2"/>
<Button android:id="@+id/app_a_wake_lock_release2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_a_release_wl2"/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/app_b_wake_lock_acquire1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_b_get_wl1"/>
<Button android:id="@+id/app_b_wake_lock_release1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_b_release_wl1"/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/app_b_wake_lock_acquire2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_b_get_wl2"/>
<Button android:id="@+id/app_b_wake_lock_release2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_b_release_wl2"/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/plug"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/plug"/>
<Button android:id="@+id/unplug"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/unplug"/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/screen_on"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/screen_on"/>
<Button android:id="@+id/screen_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/screen_off"/>
</LinearLayout>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/custom_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/custom_start" />
<Button
android:id="@+id/custom_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/custom_stop" />
</LinearLayout>
<Button android:id="@+id/dump"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:text="@string/dump"/>
<TextView
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/report_header"/>
<TextView
android:id="@+id/report_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

View File

@@ -1,109 +0,0 @@
<08><><EFBFBD>կ<EFBFBD><D5AF><EFBFBD>r<08><><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>7<10>쟑Ψ<EC9F91><CEA8>.<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>ښ<EFBFBD><DA9A><EFBFBD><EFBFBD><EFBFBD>Z<08>р<EFBFBD><D180><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD>ݙ<EFBFBD>Ǝ6<08><><EFBFBD><EFBFBD><EFBFBD>΂<EFBFBD><CE82>å<><C3A5><EFBFBD>ɗ<EFBFBD>Q<08><><EFBFBD><EFBFBD>߀<EFBFBD><DF80>@<10><>ф<EFBFBD>І<EFBFBD><D086>ѿ̲±<CCB2><C2B1>l<10>Ā<EFBFBD><C480><EFBFBD>֭<EFBFBD><08><>̳<EFBFBD><CCB3><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>˴<EFBFBD>%<08><><EFBFBD>ګ<EFBFBD><DAAB><EFBFBD>yۮ<><EFBFBD><EBB8AB>?<08><><EFBFBD><EFBFBD><E7B9A1><EFBFBD><10><><EFBFBD>،ٜ<D88C><D99C>)<08><EFBFBD><E690A9><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD>Ү<EFBFBD><D2AE><EFBFBD>.<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y"'(W<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Z<18><>ƙ<EFBFBD><C699><EFBFBD><EFBFBD><EFBFBD>"
 (2!<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD> 
V<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǀ<EFBFBD><10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Zȋ<><C88B><EFBFBD><EFBFBD>į<EFBFBD>"
 (2 <08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k 
V<08><><EFBFBD><EFBFBD><EFBFBD>㿘><10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Z<><E19E8B>ݏ<EFBFBD><DD8F>"
 (2!<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD> 
W<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Z<18><><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3>"
 (2!<08><EFBFBD><E4869D>Ɂ<EFBFBD> 
Vڜ<><DA9C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j<10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Z<18>։Ӿ<D689><D3BE><EFBFBD><EFBFBD>"
 (2!<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 
V<08><><EFBFBD><EFBFBD>≎̅<10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Z<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"
 (2!<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD> 
U<08><><EFBFBD><EFBFBD><EFBFBD>܇<EFBFBD>_<10>Ձ<EFBFBD><D581><EFBFBD><EFBFBD><EFBFBD>Z<18><><EFBFBD>҇<EFBFBD><D287><EFBFBD>z"
 (2!<>缇Ӫ 
K<08><EFBFBD><E3B4B6><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>D<18><>ƙ<EFBFBD><C699><EFBFBD><EFBFBD><EFBFBD>"
#(2<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>#I<08><><EFBFBD><ECB7BA><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>Dȋ<><C88B><EFBFBD><EFBFBD>į<EFBFBD>"
#(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k#J٢<><D9A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>D<><E19E8B>ݏ<EFBFBD><DD8F>"
#(2<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>#J<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<10><><EFBFBD><EFBFBD><EFBFBD>D<18><><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3>"
#(2<08><EFBFBD><E4869D>Ɂ<EFBFBD>#K<08><><EFBFBD>Ǟ<EFBFBD>ŝ<EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>D<18>։Ӿ<D689><D3BE><EFBFBD><EFBFBD>"
#(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#Jɳ<><C9B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>D<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"
#(2<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>#J<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>D<18><><EFBFBD>҇<EFBFBD><D287><EFBFBD>z"
#(2<>缇Ӫ#J<08><>ԯ<EFBFBD><D4AF>Β:<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"
(2<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>I<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>kǮ›<C7AE>ʟ<EFBFBD><CA9F>"
(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>kJ<08><><EFBFBD><EFBFBD><EFBD8B>y<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"
(2<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>J<08><><EFBFBD>ʓ<EFBFBD><CA93>˨<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"
(2<08><EFBFBD><E4869D>Ɂ<EFBFBD>K<08><>߰<EFBFBD><DFB0><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>J<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>݈<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"
(2<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>JУ<><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"
(2<>缇ӪK<08><>ˠ<EFBFBD><CBA0><EFBFBD><EFBFBD>M<10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD><18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"
(2<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>J̎<><CC8E><EFBFBD>{<10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD>Ǯ›<C7AE>ʟ<EFBFBD><CA9F>"
(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>kL<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"
(2<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>K<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"
(2<08><EFBFBD><E4869D>Ɂ<EFBFBD>K۔<><DB94><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y<10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>KϜݗ<CF9C><DD97><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD><18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"
(2<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>K<08>֕<EFBFBD><D695><EFBFBD><EFBFBD><EFBFBD>B<10><><EFBFBD><E9AEA3><EFBFBD><EFBFBD><18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"
(2<>缇Ӫ,Į<><C4AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̥<><CCA5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y"
(<1A><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȫ<10><><EFBFBD><EFBFBD>ȃŹ~<18><><EFBFBD>ɭ<EFBFBD><C9AD><EFBFBD>f"(2<>缇Ӫ2<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Lشͼ<D8B4><CDBC><EFBFBD><EFBFBD><EFBFBD><10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>"
-(2<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>-Jɥ<><C9A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k"
-(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k-L<08><><EFBFBD>ި<EFBFBD><DEA8><EFBFBD><EFBFBD><10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>"
-(2<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>-L<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><EFBFBD><E4869D>Ɂ<EFBFBD>"
-(2<08><EFBFBD><E4869D>Ɂ<EFBFBD>-L<08><><EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><DABD><10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
-(2<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-Lñ́<C3B1><CD81><EFBFBD><EFBFBD><EFBFBD><10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>"
-(2<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>-K<08><>ʰ<EFBFBD><CAB0><EFBFBD><EFBFBD>|<10>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><>缇Ӫ"
-(2<>缇Ӫ-"9<08><><EFBFBD>ځ<EFBFBD><DA81><EFBFBD>=̨<><CCA8><EFBFBD>ì<EFBFBD><C3AC><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08><><EFBFBD><EFBFBD><EFBFBD>έ<EFBFBD><CEAD>̨<><CCA8><EFBFBD>ì<EFBFBD><C3AC><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<><CCA8><EFBFBD>ì<EFBFBD><C3AC><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@"9<08><><EFBFBD><EFBFBD>݆<EFBFBD><DD86>S̨<><CCA8><EFBFBD>ì<EFBFBD><C3AC><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̕<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08>΀<EFBFBD><CE80><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̕<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08><><EFBFBD><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̕<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08>֜<EFBFBD><D69C><EFBFBD>ƌ<EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̕<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@"5<08>Ǚ<EFBFBD><C799>Ϣ<EFBFBD><CFA2><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>u<08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y*<08>N0@"4<08><><EFBFBD><EFBFBD>󲂜e<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>u<08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y*<08>N0@"4<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>u<08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y*<08>N0@"+<08><><EFBFBD><EFBFBD><EFBFBD>~<10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@",<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@"+<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>;<10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@",<08><><EFBFBD><EFBFBD>Ң<EFBFBD><D2A2><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@"+<08><><EFBFBD><EFBFBD>򳃨R<10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@"+<08><>øݱ<C3B8><DDB1>q<10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@",͉<><CD89>ܭ<EFBFBD><DCAD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y0@"3<08>Ļ<EFBFBD><EFBFBD><EABEB8><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2 <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y*0@"<22>ѽ<><D1BD>ɤ<EFBFBD><C9A4>a<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2 <20><><EFBFBD>ɭ<EFBFBD><C9AD><EFBFBD>f*0:<>缇Ӫ:<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@":<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@":<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϋ<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@"9<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@"9<08><><EFBFBD><EFBFBD><EFBFBD>Ɛ<EFBFBD>~<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><08>N <20>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y* <08>N0@2Y<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><>ƙ<EFBFBD><C699><EFBFBD><EFBFBD><EFBFBD>"!<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD> 
(2
 82X<08><><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD>ȋ<><C88B><EFBFBD><EFBFBD>į<EFBFBD>" <08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k 
(2
 82X<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><><E19E8B>ݏ<EFBFBD><DD8F>"!<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD> 
(2
 82Y<08><><EFBFBD><EFBFBD>޼<EFBFBD><DEBC><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3>"!<08><EFBFBD><E4869D>Ɂ<EFBFBD> 
(2
 82Y<08><>ΰÍ<CEB0><C38D><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18>։Ӿ<D689><D3BE><EFBFBD><EFBFBD>"!<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 
(2
 82Xդ<><D5A4>ã<EFBFBD><C3A3><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"!<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD> 
(2
 82X<08>ªߍ<C2AA><DF8D><EFBFBD><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD>҇<EFBFBD><D287><EFBFBD>z"!<>缇Ӫ 
(2
 825<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƭ<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>W(2
 82X<08><><EFBFBD>߆<EFBFBD><DF86><EFBFBD>`<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><>ƙ<EFBFBD><C699><EFBFBD><EFBFBD><EFBFBD>"!<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD> 
(2
 82W<08>ޟ<EFBFBD>Ԡ<EFBFBD><D4A0>d<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD>ȋ<><C88B><EFBFBD><EFBFBD>į<EFBFBD>" <08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k 
(2
 82X<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><><E19E8B>ݏ<EFBFBD><DD8F>"!<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD> 
(2
 82Y<08><><EFBFBD><EFBFBD><EEACB1><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3>"!<08><EFBFBD><E4869D>Ɂ<EFBFBD> 
(2
 82Y<08><>̴׳<CCB4><D7B3><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18>։Ӿ<D689><D3BE><EFBFBD><EFBFBD>"!<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 
(2
 82W<08><><EFBFBD><EFBFBD><EFBFBD>ȓ<EFBFBD>P<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"!<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD> 
(2
 82X<08><><EFBFBD><EFBFBD><EFBFBD>˘<EFBFBD><CB98><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD>҇<EFBFBD><D287><EFBFBD>z"!<>缇Ӫ 
(2
 82U<08><><EFBFBD>۲<EFBFBD><DBB2><EFBFBD><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><>ƙ<EFBFBD><C699><EFBFBD><EFBFBD><EFBFBD>"!<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD> 
(2 
82T<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD>ȋ<><C88B><EFBFBD><EFBFBD>į<EFBFBD>" <08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k 
(2 
82T<08><><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><><E19E8B>ݏ<EFBFBD><DD8F>"!<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD> 
(2 
82T҈π<D288><CF80><EFBFBD><EFBFBD>D<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><C2A3>"!<08><EFBFBD><E4869D>Ɂ<EFBFBD> 
(2 
82U<08><>˄<CB84><E998BF><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18>։Ӿ<D689><D3BE><EFBFBD><EFBFBD>"!<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 
(2 
82S˩<>ޯ<EFBFBD><DEAF><EFBFBD>&<10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"!<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD> 
(2 
82Tά<><CEAC><EFBFBD><E194BA><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD>҇<EFBFBD><D287><EFBFBD>z"!<>缇Ӫ 
(2 
82#<08><><EFBFBD><EFBFBD>ɱ<EFBFBD><C9B1><EFBFBD><10><>Ӥ<EFBFBD><D3A4><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>W(82#ޞ<><DE9E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD>ß<EFBFBD><C39F><EFBFBD>F<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82"<><E4A39E><EFBFBD><EFBFBD><EFBFBD>r<10><><EFBFBD>ß<EFBFBD><C39F><EFBFBD>F<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82*<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӌ3<10><><EFBFBD>ß<EFBFBD><C39F><EFBFBD>F<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(2%82*<08>М<EFBFBD><D09C><EFBFBD>Ċ<10><><EFBFBD>ß<EFBFBD><C39F><EFBFBD>F<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(2%82"<08><EFBFBD><E891B2><EFBFBD><EFBFBD>+<10><><EFBFBD>ß<EFBFBD><C39F><EFBFBD>F<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82J<08><>܎<EFBFBD><DC8E><EFBFBD><EFBFBD><EFBFBD><10><>Ƅת<C684><D7AA><EFBFBD><18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>'(2'82H<08><><EFBFBD><EFBFBD>Қ<EFBFBD><D29A>q<10><>Ƅת<C684><D7AA><EFBFBD>Ǯ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k'(2'82J<08><><EFBFBD>ą<EFBFBD><C485><EFBFBD><EFBFBD><10><>Ƅת<C684><D7AA><EFBFBD><18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>'(2'82I<08>ë<EFBFBD><C3AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>Ƅת<C684><D7AA><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>'(2'82I<08><><EFBFBD>ɭK<10><>Ƅת<C684><D7AA><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'(2'82H<08><><EFBFBD>ޥ<EFBFBD><DEA5><EFBFBD>\<10><>Ƅת<C684><D7AA><EFBFBD><18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>'(2'82J<08><><EFBFBD><EFBFBD><ECA68A><EFBFBD><10><>Ƅת<C684><D7AA><EFBFBD><18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ'(2'82<><08><><EFBFBD><EFBFBD><EFBFBD>ʐ<EFBFBD><CA90><10><><EFBFBD><EFBFBD>̽<EFBFBD>¡<18><><EFBFBD>ɭ<EFBFBD><C9AD><EFBFBD>f"<>缇Ӫ"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282<><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y<10><><EFBFBD><EFBFBD>̽<EFBFBD>¡<18><><EFBFBD>ɭ<EFBFBD><C9AD><EFBFBD>f"<>缇Ӫ"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282M<08><><EFBFBD><EFBFBD><EFBFBD>'<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(2
82L<08>ϗꤦݯ5<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǯ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(2
82Nø<>͝<EFBFBD><CD9D><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(2
82LŸ<><C29F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>(2
82N<08><><EFBFBD><EFBFBD><EFBFBD>١<EFBFBD><D9A1><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(2
82M<08><><EFBFBD><EFBFBD><EFBFBD><E9A58A><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(2
82M<08><>܋<EFBFBD><DC8B>˄<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ(2
82<><08><><EFBFBD><EA81B4><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD>ɭ<EFBFBD><C9AD><EFBFBD>f"<>缇Ӫ"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282,ܛ<><DC9B><EFBFBD><EFBFBD>ň<EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282+ټ<><D9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>ӏ<EFBFBD><D38F><EFBFBD><EFBFBD><EFBFBD>9<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282.<08><><EFBFBD>˛ղ<CB9B>^<10>ӏ<EFBFBD><D38F><EFBFBD><EFBFBD><EFBFBD>9<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(2
82/<08><><EFBFBD><EFBFBD><EFBFBD>Č<EFBFBD>#󪷎<><F3AAB78E><EFBFBD>ъ<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(2
82+<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>y󪷎<><F3AAB78E><EFBFBD>ъ<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282"Н<>ʢ<EFBFBD>ކ#<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82I<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(282Hސ<><DE90>Ŋ<EFBFBD><C58A><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>KǮ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(282G<08><>ܰ<EFBFBD><DCB0><EFBFBD><EFBFBD>{<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>(282I<08><><EFBFBD><EFBFBD><EFBFBD>̚<EFBFBD><CC9A><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282H<08>Ґ<EFBFBD><D290><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>E<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ(282 <08>ڞ<EFBFBD><DA9E><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(282"<08><><EFBFBD>ٟ<EFBFBD><D99F><EFBFBD><EFBFBD><10><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(282!<08>ɨ<EFBFBD><EFBFBD><10><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(282"ՙ<><D599><EFBFBD>̷<EFBFBD><CCB7><10><EFBFBD><E4869D>Ɂ<EFBFBD>(282!<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282!<08><><EFBFBD><EFBFBD>ѾۛL<10><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(282!<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>O<>缇Ӫ(282+<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282+Ӯ<><D3AE><EFBFBD><EFBFBD>ɳ=<10><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282+<08>؎<EFBFBD><D88E><EFBFBD><EFBFBD><EFBFBD>c<10><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282,<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˊ<10><EFBFBD><E4869D>Ɂ<EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282+<08><><EFBFBD><EFBFBD><EFBFBD>묩u<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282,<08>ń<EFBFBD><C584><EFBFBD><EFBFBD>ޠ<10><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282,<08><>ئ<EFBFBD><D8A6><EFBFBD><EFBFBD><EFBFBD><>缇Ӫ<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(282#<08>Ԇ<EFBFBD><D486><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD>ۛ<EFBFBD><DB9B><EFBFBD><EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82,<08><><EFBFBD>Ч<EFBFBD><10><><EFBFBD>ۛ<EFBFBD><DB9B><EFBFBD><EFBFBD><18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(2 82#<08><><EFBFBD><EFBFBD><EFBFBD>֪<EFBFBD><D6AA><10><>ýب<C3BD><D8A8>=<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82I<08>͘<EFBFBD><CD98>ڐ<EFBFBD><DA90><10><>ýب<C3BD><D8A8>=<18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(282H<08>;ܲ<CDBE>ˮ<EFBFBD><10><>ýب<C3BD><D8A8>=Ǯ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(282I̙<><CC99><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>ýب<C3BD><D8A8>=<18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(282Gڴ<><DAB4><EFBFBD>ࠣY<10><>ýب<C3BD><D8A8>=<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>(282I<08><><EFBFBD>р<EFBFBD><D180><EFBFBD><EFBFBD><10><>ýب<C3BD><D8A8>=<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282G׏<><D78F><EFBFBD>ɭ<EFBFBD><10><>ýب<C3BD><D8A8>=<18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(282H<08><>ϛ饸<CF9B>U<10><>ýب<C3BD><D8A8>=<18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ(282"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>݃<EFBFBD><DD83>ϙs<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82I<08><><EFBFBD>ń<EFBFBD>·<EFBFBD><10><>݃<EFBFBD><DD83>ϙs<18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>݃<EFBFBD><DD83>ϙsǮ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<10><>݃<EFBFBD><DD83>ϙs<18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(282G<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>݃<EFBFBD><DD83>ϙs<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>(282H<08><><EFBFBD>ˠ<EFBFBD><CBA0><EFBFBD> <10><>݃<EFBFBD><DD83>ϙs<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282G<08><><EFBFBD><EFBFBD><EFBFBD>ʍ<EFBFBD><10><>݃<EFBFBD><DD83>ϙs<18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'<10><>݃<EFBFBD><DD83>ϙs<18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ(282#<><E4AAA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>߮<EFBFBD><DFAE>Ͽ<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82H<08><><EFBFBD><EFBFBD><EFBFBD>Ϫ<EFBFBD>;<10><>߮<EFBFBD><DFAE>Ͽ<18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(282G<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@<10><>߮<EFBFBD><DFAE>ϿǮ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-<10><>߮<EFBFBD><DFAE>Ͽ<18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(282G<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I<10><>߮<EFBFBD><DFAE>Ͽ<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>(282H<08>ێ<EFBFBD><DB8E><EFBFBD><EFBFBD><EFBFBD>
<10><>߮<EFBFBD><DFAE>Ͽ<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282G<08><><EFBFBD><EFBFBD><EC92B3><10><>߮<EFBFBD><DFAE>Ͽ<18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(282H<08>ש<EFBFBD><D7A9><EFBFBD><EFBFBD><EFBFBD>b<10><>߮<EFBFBD><DFAE>Ͽ<18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ(282#<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18>ٕ<EFBFBD><D995><EFBFBD><EFBFBD><EFBFBD>y(82H<08><>ֽ<EFBFBD><D6BD>Ѓq<10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18>Ӎܢ<D38D><DCA2><EFBFBD><EFBFBD>"<08><>ߪ<EFBFBD><DFAA><EFBFBD><EFBFBD><EFBFBD>(282G<08><><EFBFBD><EFBFBD><EFBFBD>״<EFBFBD><10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>KǮ›<C7AE>ʟ<EFBFBD><CA9F>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k(282I<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͹<EFBFBD><10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18><><EFBFBD><EFBFBD>Ó<EFBFBD><C393><EFBFBD>"<08><><EFBFBD>ä<EFBFBD><C3A4><EFBFBD><EFBFBD>(282H<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I"<08><EFBFBD><E4869D>Ɂ<EFBFBD>(282H<08><><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(282G<08>ɬ<EFBFBD><C9AC><EFBFBD><EFBFBD><EFBFBD>p<10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18><EFBFBD><E98BBF><EFBFBD><EFBFBD>"<08><><EFBFBD><EFBFBD><EFBFBD>䤿<EFBFBD>(282H<08>ú<EFBFBD><C3BA><EFBFBD><EFBFBD><EFBFBD>6<10><><EFBFBD>ݎ<EFBFBD><DD8E><EFBFBD>K<18><><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD>"<>缇Ӫ(28:<08><><EFBFBD>،ٜ<D88C><D99C>*:<08>ؒ<EFBFBD><D892><EFBFBD> (<28>:<08><>Ȁ<EFBFBD><C880><EFBFBD><EFBFBD><EFBFBD> (<28>:<08><><EFBFBD><EFBFBD><EFBFBD><E2AFA2> (<28> :<08><>Ơ<EFBFBD><C6A0><EFBFBD><EFBFBD><EFBFBD> (<28> :<08><><EFBFBD><EFBFBD><EFBFBD>η<EFBFBD>B (<28>
:<08>ν<EFBFBD><CEBD><EFBFBD><EFBFBD><EFBFBD> (<28>:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>m (<28>:<08>ƺ<EFBFBD><C6BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28>
:<08><><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD> (<28>:<08>ï<EFBFBD><C3AF><EFBFBD><EFBFBD><EFBFBD>w (<28>
:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28>:<08><><EFBFBD>ܦ<EFBFBD><DCA6><EFBFBD><EFBFBD>(:<08>ڹ<EFBFBD><DAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(d:<08><><EFBFBD><EFBFBD>ɩ<EFBFBD><C9A9><EFBFBD> (<28> :<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>E (<28>:<08><><EFBFBD>͘<EFBFBD><CD98><EFBFBD> (<28>:<08><><EFBFBD><EFBFBD><E18D89><EFBFBD>(:<08>ҧ<EFBFBD><D2A7><EFBFBD><EFBFBD><EFBFBD> (:<08>Ā<EFBFBD><C480><EFBFBD>֭<EFBFBD>:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2:N<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<10><><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><10><><EFBFBD>͘<EFBFBD><CD98><EFBFBD><10>ؒ<EFBFBD><D892><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>m<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>E<10><><EFBFBD><EFBFBD>ɩ<EFBFBD><C9A9><EFBFBD>:D<08><><EFBFBD><EFBFBD>ͧ<EFBFBD>Ћ7<10>ƺ<EFBFBD><C6BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10>ï<EFBFBD><C3AF><EFBFBD><EFBFBD><EFBFBD>w<10><><EFBFBD><EFBFBD><EFBFBD><E2AFA2><10><>Ơ<EFBFBD><C6A0><EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><EFBFBD>η<EFBFBD>B:³ћ<C2B3><D19B>Ս<EFBFBD> (<28>:9<08><><EFBFBD><ED9B8F><EFBFBD>X-<10><><EFBFBD>ܦ<EFBFBD><DCA6><EFBFBD><EFBFBD><10>ڹ<EFBFBD><DAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><10><>Ȁ<EFBFBD><C880><EFBFBD><EFBFBD><EFBFBD><10>ν<EFBFBD><CEBD><EFBFBD><EFBFBD><EFBFBD>:<08>ƒ<EFBFBD><C283><EFBFBD>ȯ<EFBFBD> (<28>:ϑ<><CF91>θ<EFBFBD><CEB8>_ (<28>:<08><EFBFBD><E99B8C><EFBFBD><EFBFBD><EFBFBD>(:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(:<08>ښ<EFBFBD><DA9A><EFBFBD><EFBFBD><EFBFBD>Z:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><08>N:<08><><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><08>N:å<><C3A5><EFBFBD>ɗ<EFBFBD>Q:<08><>ф<EFBFBD>І<EFBFBD><D086>:<08>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-:<08><><EFBFBD><EFBFBD>񽞒<EFBFBD>(:<08>ˣͥ<CBA3><CDA5><EFBFBD><EFBFBD>(:<08><><EFBFBD><EFBFBD>ȃŹ~(:<08>񒁿<EFBFBD><F19281BF>ܺ(:<08><><EFBFBD><EFBFBD><EFBFBD>˴<EFBFBD>% :<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̕<EFBFBD><08>N:"<08>摨휘<E691A8><10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+<10><><EFBFBD>ċ<EFBFBD><C48B><EFBFBD>:<08><><EFBFBD>ċ<EFBFBD><C48B><EFBFBD> (:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+ (:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (:<08><><EFBFBD><EFBFBD><EFBFBD>ʴ<EFBFBD><08>N:<08><><EFBFBD><EFBFBD><EFBFBD>遏`
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:<08><><EFBFBD><EFBFBD><E3B9A7><EFBFBD>
<10><><EFBFBD><EFBFBD>ͧ<EFBFBD>Ћ:<08><>֓<EFBFBD><D693>·<EFBFBD>
³ћ<C2B3><D19B>Ս<EFBFBD>:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <10><><EFBFBD><ED9B8F><EFBFBD>X:<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k
<10>ƒ<EFBFBD><C283><EFBFBD>ȯ<EFBFBD>:<08><>ڄ<EFBFBD><DA84><EFBFBD><EFBFBD>4 ϑ<><CF91>θ<EFBFBD><CEB8>_:<08><>œ<EFBFBD><C29C><EFBFBD><EFBFBD>
((:<08><><EFBFBD>˹<EFBFBD><CBB9><EFBFBD>Y
((:<08><><EFBFBD><E6A48F><EFBFBD><EFBFBD>

View File

@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources>
<string name="app_name">Statsd Dogfood</string>
<string name="statsd_running">Statsd Running</string>
<string name="statsd_not_running">Statsd NOT Running</string>
<string name="push_config">Push baseline config</string>
<string name="set_receiver">Set pendingintent</string>
<string name="remove_receiver">Remove pendingintent</string>
<string name="app_a_foreground">App A foreground</string>
<string name="app_b_foreground">App B foreground</string>
<string name="app_a_get_wl1">App A get wl_1</string>
<string name="app_a_release_wl1">App A release wl_1</string>
<string name="app_a_get_wl2">App A get wl_2</string>
<string name="app_a_release_wl2">App A release wl_2</string>
<string name="app_b_get_wl1">App B get wl_1</string>
<string name="app_b_release_wl1">App B release wl_1</string>
<string name="app_b_get_wl2">App B get wl_2</string>
<string name="app_b_release_wl2">App B release wl_2</string>
<string name="plug">Plug</string>
<string name="unplug">Unplug</string>
<string name="screen_on">Screen On</string>
<string name="screen_off">Screen Off</string>
<string name="custom_start">App hook start</string>
<string name="custom_stop">App hook stop</string>
<string name="dump">DumpReport</string>
<string name="report_header">Report details</string>
</resources>

View File

@@ -1,158 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.dogfood;
import android.text.format.DateFormat;
import com.android.os.StatsLog;
import java.util.List;
public class DisplayProtoUtils {
public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
sb.append("ConfigKey: ");
if (reports.hasConfigKey()) {
com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getId())
.append("\n");
}
for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
append("\n");
sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
sb.append("\n\n");
sb.append("metric id: ").append(log.getMetricId()).append("\n");
switch (log.getDataCase()) {
case DURATION_METRICS:
sb.append("Duration metric data\n");
displayDurationMetricData(sb, log);
break;
case EVENT_METRICS:
sb.append("Event metric data\n");
displayEventMetricData(sb, log);
break;
case COUNT_METRICS:
sb.append("Count metric data\n");
displayCountMetricData(sb, log);
break;
case GAUGE_METRICS:
sb.append("Gauge metric data\n");
displayGaugeMetricData(sb, log);
break;
case VALUE_METRICS:
sb.append("Value metric data\n");
displayValueMetricData(sb, log);
break;
case DATA_NOT_SET:
sb.append("No metric data\n");
break;
}
}
}
}
public static String getDateStr(long nanoSec) {
return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
}
private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
sb.append(dimensionValue.getField()).append(":");
if (dimensionValue.hasValueBool()) {
sb.append(dimensionValue.getValueBool());
} else if (dimensionValue.hasValueFloat()) {
sb.append(dimensionValue.getValueFloat());
} else if (dimensionValue.hasValueInt()) {
sb.append(dimensionValue.getValueInt());
} else if (dimensionValue.hasValueStr()) {
sb.append(dimensionValue.getValueStr());
} else if (dimensionValue.hasValueTuple()) {
sb.append("{");
for (StatsLog.DimensionsValue child :
dimensionValue.getValueTuple().getDimensionsValueList()) {
displayDimension(sb, child);
}
sb.append("}");
}
sb.append(" ");
}
public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
= log.getDurationMetrics();
sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
sb.append("dimension_in_what: ");
displayDimension(sb, duration.getDimensionsInWhat());
sb.append("\n");
if (duration.hasDimensionsInCondition()) {
sb.append("dimension_in_condition: ");
displayDimension(sb, duration.getDimensionsInCondition());
sb.append("\n");
}
for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
.append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getDurationNanos()).append(" ns\n");
}
}
}
public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
= log.getCountMetrics();
sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
sb.append("dimension_in_what: ");
displayDimension(sb, count.getDimensionsInWhat());
sb.append("\n");
if (count.hasDimensionsInCondition()) {
sb.append("dimension_in_condition: ");
displayDimension(sb, count.getDimensionsInCondition());
sb.append("\n");
}
for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
.append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getCount()).append("\n");
}
}
}
public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
sb.append("Display me!");
}
public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
sb.append("Display me!");
}
}

View File

@@ -1,361 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.dogfood;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.IntentService;
import android.app.StatsManager;
import android.app.StatsManager.StatsUnavailableException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.util.StatsLog;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.os.IStatsManager;
import android.os.ServiceManager;
import java.io.InputStream;
import static com.android.statsd.dogfood.DisplayProtoUtils.displayLogReport;
public class MainActivity extends Activity {
private final static String TAG = "StatsdDogfood";
private final static long CONFIG_ID = 987654321;
final int[] mUids = {11111111, 2222222};
StatsManager mStatsManager;
TextView mReportText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockAcquire(0, "wl_1");
}
});
findViewById(R.id.app_b_wake_lock_acquire1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockAcquire(1, "wl_1");
}
});
findViewById(R.id.app_a_wake_lock_acquire2).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockAcquire(0, "wl_2");
}
});
findViewById(R.id.app_b_wake_lock_acquire2).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockAcquire(1, "wl_2");
}
});
findViewById(R.id.app_a_wake_lock_release1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockRelease(0, "wl_1");
}
});
findViewById(R.id.app_b_wake_lock_release1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockRelease(1, "wl_1");
}
});
findViewById(R.id.app_a_wake_lock_release2).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockRelease(0, "wl_2");
}
});
findViewById(R.id.app_b_wake_lock_release2).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
onWakeLockRelease(1, "wl_2");
}
});
findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_AC);
}
});
findViewById(R.id.unplug).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_NONE);
}
});
findViewById(R.id.screen_on).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON);
}
});
findViewById(R.id.screen_off).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF);
}
});
findViewById(R.id.custom_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StatsLog.logStart(8);
}
});
findViewById(R.id.custom_stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StatsLog.logStop(8);
}
});
mReportText = (TextView) findViewById(R.id.report_text);
findViewById(R.id.dump).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!statsdRunning()) {
return;
}
if (mStatsManager != null) {
try {
byte[] data = mStatsManager.getReports(CONFIG_ID);
if (data != null) {
displayData(data);
return;
}
} catch (StatsUnavailableException e) {
Log.e(TAG, "Failed to get data from statsd", e);
}
mReportText.setText("Failed!");
}
}
});
findViewById(R.id.push_config).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
if (!statsdRunning()) {
return;
}
Resources res = getResources();
InputStream inputStream = res.openRawResource(R.raw.statsd_baseline_config);
byte[] config = new byte[inputStream.available()];
inputStream.read(config);
if (mStatsManager != null) {
try {
mStatsManager.addConfig(CONFIG_ID, config);
Toast.makeText(
MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
} catch (StatsUnavailableException | IllegalArgumentException e) {
Toast.makeText(MainActivity.this, "Config push FAILED!",
Toast.LENGTH_LONG).show();
}
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, "failed to read config", Toast.LENGTH_LONG);
}
}
});
PendingIntent pi = PendingIntent.getService(this, 0,
new Intent(this, ReceiverIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
findViewById(R.id.set_receiver).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
if (!statsdRunning()) {
return;
}
if (mStatsManager != null) {
try {
mStatsManager.setFetchReportsOperation(pi, CONFIG_ID);
Toast.makeText(MainActivity.this,
"Receiver specified to pending intent", Toast.LENGTH_LONG)
.show();
} catch (StatsUnavailableException e) {
Toast.makeText(MainActivity.this, "Statsd did not set receiver",
Toast.LENGTH_LONG)
.show();
}
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, "failed to set receiver", Toast.LENGTH_LONG);
}
}
});
findViewById(R.id.remove_receiver).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
if (!statsdRunning()) {
return;
}
if (mStatsManager != null) {
try {
mStatsManager.setFetchReportsOperation(null, CONFIG_ID);
Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
.show();
} catch (StatsUnavailableException e) {
Toast.makeText(MainActivity.this, "Statsd did not remove receiver",
Toast.LENGTH_LONG)
.show();
}
}
} catch (Exception e) {
Toast.makeText(
MainActivity.this, "failed to remove receiver", Toast.LENGTH_LONG);
}
}
});
mStatsManager = (StatsManager) getSystemService("stats");
}
private boolean statsdRunning() {
if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
Log.d(TAG, "Statsd not running");
Toast.makeText(MainActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
@Override
public void onNewIntent(Intent intent) {
Log.d(TAG, "new intent: " + intent.getIntExtra("pkg", 0));
int pkg = intent.getIntExtra("pkg", 0);
String name = intent.getStringExtra("name");
if (intent.hasExtra("acquire")) {
onWakeLockAcquire(pkg, name);
} else if (intent.hasExtra("release")) {
onWakeLockRelease(pkg, name);
}
}
private void displayData(byte[] data) {
com.android.os.StatsLog.ConfigMetricsReportList reports = null;
boolean good = false;
if (data != null) {
try {
reports = com.android.os.StatsLog.ConfigMetricsReportList.parseFrom(data);
good = true;
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
// display it in the text view.
}
}
int size = data == null ? 0 : data.length;
StringBuilder sb = new StringBuilder();
sb.append(good ? "Proto parsing OK!" : "Proto parsing Error!");
sb.append(" size:").append(size).append("\n");
if (good && reports != null) {
displayLogReport(sb, reports);
mReportText.setText(sb.toString());
}
}
private void onWakeLockAcquire(int id, String name) {
if (id > 1) {
Log.d(TAG, "invalid pkg id");
return;
}
int[] uids = new int[]{mUids[id]};
String[] tags = new String[]{"acquire"};
StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
StringBuilder sb = new StringBuilder();
sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
.append(", ").append(name).append(", 1);");
Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
}
private void onWakeLockRelease(int id, String name) {
if (id > 1) {
Log.d(TAG, "invalid pkg id");
return;
}
int[] uids = new int[]{mUids[id]};
String[] tags = new String[]{"release"};
StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
StringBuilder sb = new StringBuilder();
sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
.append(", ").append(name).append(", 0);");
Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
}
public static class ReceiverIntentService extends IntentService {
public ReceiverIntentService() {
super("ReceiverIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "Received notification that we should call getData");
}
}
}

View File

@@ -1,37 +0,0 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
android_app {
name: "StatsdLoadtest",
platform_apis: true,
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
static_libs: [
"platformprotoslite",
"statsdprotolite",
],
certificate: "platform",
privileged: true,
dex_preopt: {
enabled: false,
},
optimize: {
enabled: false,
},
}

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.statsd.loadtest"
android:sharedUserId="android.uid.system"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.DUMP" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".LoadtestActivity"
android:label="@string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".LoadtestActivity$PusherAlarmReceiver" />
<receiver android:name=".LoadtestActivity$StopperAlarmReceiver"/>
<receiver android:name=".PerfData$PerfAlarmReceiver"/>
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,208 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/outside"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:orientation="vertical">
<requestFocus />
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:textSize="30dp"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/replication_label" />
<EditText
android:id="@+id/replication"
android:inputType="number"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLength="4"
android:text="@integer/replication_default"
android:textSize="30dp"/>
</LinearLayout>
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:textSize="30dp"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/bucket_label" />
<Spinner
android:id="@+id/bucket_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:prompt="@string/bucket_label"/>
</LinearLayout>
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:textSize="30dp"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/period_label" />
<EditText
android:id="@+id/period"
android:inputType="number"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="3"
android:text="@integer/period_default"
android:textSize="30dp"/>
</LinearLayout>
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:textSize="30dp"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/burst_label" />
<EditText
android:id="@+id/burst"
android:inputType="number"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLength="4"
android:text="@integer/burst_default"
android:textSize="30dp"/>
</LinearLayout>
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:textSize="30dp"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/duration_label" />
<EditText
android:id="@+id/duration"
android:inputType="number"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="4"
android:text="@integer/duration_default"
android:textSize="30dp"/>
</LinearLayout>
<CheckBox
android:id="@+id/placebo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/placebo"
android:checked="false" />
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/include_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/count"
android:checked="true"/>
<CheckBox
android:id="@+id/include_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/duration"
android:checked="true"/>
<CheckBox
android:id="@+id/include_event"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/event"
android:checked="true"/>
<CheckBox
android:id="@+id/include_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/value"
android:checked="true"/>
<CheckBox
android:id="@+id/include_gauge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/gauge"
android:checked="true"/>
</LinearLayout>
<Space
android:layout_width="1dp"
android:layout_height="30dp"/>
<Button
android:id="@+id/start_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffff0000"
android:text="@string/start"
android:textSize="50dp"/>
<Space
android:layout_width="1dp"
android:layout_height="30dp"/>
<Space
android:layout_width="1dp"
android:layout_height="30dp"/>
<TextView
android:id="@+id/report_text"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30dp"
android:gravity="left"
android:padding="5dip"
/>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources>
<integer name="burst_default">1</integer>
<integer name="period_default">2</integer>
<integer name="replication_default">1</integer>
<integer name="duration_default">240</integer>
</resources>

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources>
<string name="app_name">Statsd Loadtest</string>
<string name="bucket_label">bucket size (mins):&#160;</string>
<string name="burst_label">burst:&#160;</string>
<string name="bucket_default">FIVE_MINUTES</string>
<string name="placebo">placebo</string>
<string name="period_label">logging period (secs):&#160;</string>
<string name="replication_label">metric replication:&#160;</string>
<string name="duration_label">test duration (mins):&#160;</string>
<string name="start"> &#160;Start&#160; </string>
<string name="stop"> &#160;Stop&#160; </string>
<string name="count"> count </string>
<string name="duration"> duration </string>
<string name="event"> event </string>
<string name="value"> value </string>
<string name="gauge"> gauge </string>
</resources>

View File

@@ -1,99 +0,0 @@
#!/bin/sh
#
# Script that measures statsd's PSS under an increasing number of metrics.
# Globals.
pss=""
pid=""
# Starts the loadtest.
start_loadtest() {
echo "Starting loadtest"
adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "start"
}
# Stops the loadtest.
stop_loadtest() {
echo "Stopping loadtest"
adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "stop"
}
# Sets the metrics replication.
# Arguments:
# $1: The replication factor.
set_replication() {
adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "set_replication" --ei "replication" "${1}"
echo "Replication set to ${1}"
}
# Reads statsd's pid and PSS.
update_pid_and_pss() {
# Command that reads the PSS for statsd. This also gives us its pid.
get_mem=$(adb shell dumpsys meminfo |grep statsd)
# Looks for statsd's pid.
regex="([0-9,]+)K: statsd \(pid ([0-9]+)\).*"
if [[ $get_mem =~ $regex ]]; then
pss=$(echo "${BASH_REMATCH[1]}" | tr -d , | sed 's/\.//g')
pid=$(echo "${BASH_REMATCH[2]}")
else
echo $cmd doesnt match $regex
fi
}
# Kills statsd.
# Assumes the pid has been set.
kill_statsd() {
echo "Killing statsd (pid ${pid})"
adb shell kill -9 "${pid}"
}
# Main loop.
main() {
start_time=$(date +%s)
values=()
stop_loadtest
echo ""
echo "********************* NEW LOADTEST ************************"
update_pid_and_pss
for replication in 1 2 4 8 16 32 64 128 256 512 1024 2048 4096
do
echo "**** Starting test at replication ${replication} ****"
# (1) Restart statsd. This will ensure its state is empty.
kill_statsd
sleep 3 # wait a bit for it to restart
update_pid_and_pss
echo "Before the test, statsd's PSS is ${pss}"
# (2) Set the replication.
set_replication "${replication}"
sleep 1 # wait a bit
# (3) Start the loadtest.
start_loadtest
# (4) Wait several seconds, then read the PSS.
sleep 100 && update_pid_and_pss
echo "During the test, statsd's PSS is ${pss}"
values+=(${pss})
echo "Values: ${values[@]}"
# (5) Stop loadtest.
stop_loadtest
sleep 2
echo ""
done
end_time=$(date +%s)
echo "Completed loadtest in $((${end_time} - ${start_time})) seconds."
values_as_str=$(IFS=$'\n'; echo "${values[*]}")
echo "The PSS values are:"
echo "${values_as_str}"
echo ""
}
main

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.annotation.Nullable;
import android.content.Context;
import android.util.Log;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BatteryDataRecorder extends PerfDataRecorder {
private static final String TAG = "loadtest.BatteryDataRecorder";
private static final String DUMP_FILENAME = TAG + "_dump.tmp";
public BatteryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
int burst, boolean includeCountMetric, boolean includeDurationMetric,
boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
}
@Override
public void startRecording(Context context) {
// Reset batterystats.
runDumpsysStats(context, DUMP_FILENAME, "batterystats", "--reset");
}
@Override
public void onAlarm(Context context) {
// Nothing to do as for battery, the whole data is in the final dumpsys call.
}
@Override
public void stopRecording(Context context) {
StringBuilder sb = new StringBuilder();
// Don't use --checkin.
runDumpsysStats(context, DUMP_FILENAME, "batterystats");
readDumpData(context, DUMP_FILENAME, new BatteryStatsParser(), sb);
writeData(context, "battery_", "time,battery_level", sb);
}
}

View File

@@ -1,113 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.annotation.Nullable;
import android.util.Log;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BatteryStatsParser implements PerfParser {
private static final Pattern LINE_PATTERN =
Pattern.compile("\\s*\\+*(\\S*)\\s\\(\\d+\\)\\s(\\d\\d\\d)\\s.*");
private static final Pattern TIME_PATTERN =
Pattern.compile("(\\d+)?(h)?(\\d+)?(m)?(\\d+)?(s)?(\\d+)?(ms)?");
private static final String TAG = "loadtest.BatteryStatsParser";
private boolean mHistoryStarted;
private boolean mHistoryEnded;
public BatteryStatsParser() {
}
@Override
@Nullable
public String parseLine(String line) {
if (mHistoryEnded) {
return null;
}
if (!mHistoryStarted) {
if (line.contains("Battery History")) {
mHistoryStarted = true;
}
return null;
}
if (line.isEmpty()) {
mHistoryEnded = true;
return null;
}
Matcher lineMatcher = LINE_PATTERN.matcher(line);
if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
if (lineMatcher.group(1).equals("0")) {
return "0," + lineMatcher.group(2) + "\n";
} else {
Matcher timeMatcher = TIME_PATTERN.matcher(lineMatcher.group(1));
if (timeMatcher.find()) {
Long time = getTime(lineMatcher.group(1));
if (time != null) {
return time + "," + lineMatcher.group(2) + "\n";
} else {
return null; // bad time
}
} else {
return null; // bad or no time
}
}
}
return null;
}
@Nullable
private Long getTime(String group) {
if ("0".equals(group)) {
return 0L;
}
Matcher timeMatcher = TIME_PATTERN.matcher(group);
if (!timeMatcher.find()) {
return null;
}
// Get rid of "ms".
String[] matches = group.split("ms", -1);
if (matches.length > 1) {
group = matches[0];
}
long time = 0L;
matches = group.split("h");
if (matches.length > 1) {
time += Long.parseLong(matches[0]) * 60 * 60 * 1000; // hours
group = matches[1];
}
matches = group.split("m");
if (matches.length > 1) {
time += Long.parseLong(matches[0]) * 60 * 1000; // minutes
group = matches[1];
}
matches = group.split("s");
if (matches.length > 1) {
time += Long.parseLong(matches[0]) * 1000; // seconds
group = matches[1];
}
if (!group.isEmpty()) {
time += Long.parseLong(group); // milliseconds
}
return time;
}
}

View File

@@ -1,314 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import com.android.internal.os.StatsdConfigProto.Predicate;
import com.android.internal.os.StatsdConfigProto.CountMetric;
import com.android.internal.os.StatsdConfigProto.DurationMetric;
import com.android.internal.os.StatsdConfigProto.MetricConditionLink;
import com.android.internal.os.StatsdConfigProto.EventMetric;
import com.android.internal.os.StatsdConfigProto.GaugeMetric;
import com.android.internal.os.StatsdConfigProto.ValueMetric;
import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
import com.android.internal.os.StatsdConfigProto.SimplePredicate;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import java.io.InputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Creates StatsdConfig protos for loadtesting.
*/
public class ConfigFactory {
public static class ConfigMetadata {
public final byte[] bytes;
public final int numMetrics;
public ConfigMetadata(byte[] bytes, int numMetrics) {
this.bytes = bytes;
this.numMetrics = numMetrics;
}
}
public static final long CONFIG_ID = 123456789;
private static final String TAG = "loadtest.ConfigFactory";
private final StatsdConfig mTemplate;
public ConfigFactory(Context context) {
// Read the config template from the resoures.
Resources res = context.getResources();
byte[] template = null;
StatsdConfig templateProto = null;
try {
InputStream inputStream = res.openRawResource(R.raw.loadtest_config);
template = new byte[inputStream.available()];
inputStream.read(template);
templateProto = StatsdConfig.parseFrom(template);
} catch (IOException e) {
Log.e(TAG, "Unable to read or parse loadtest config template. Using an empty config.");
}
mTemplate = templateProto == null ? StatsdConfig.newBuilder().build() : templateProto;
Log.d(TAG, "Loadtest template config: " + mTemplate);
}
/**
* Generates a config.
*
* All configs are based on the same template.
* That template is designed to make the most use of the set of atoms that {@code SequencePusher}
* pushes, and to exercise as many of the metrics features as possible.
* Furthermore, by passing a replication factor to this method, one can artificially inflate
* the number of metrics in the config. One can also adjust the bucket size for aggregate
* metrics.
*
* @param replication The number of times each metric is replicated in the config.
* If the config template has n metrics, the generated config will have n * replication
* ones
* @param bucketMillis The bucket size, in milliseconds, for aggregate metrics
* @param placebo If true, only return an empty config
* @return The serialized config and the number of metrics.
*/
public ConfigMetadata getConfig(int replication, TimeUnit bucket, boolean placebo,
boolean includeCount, boolean includeDuration, boolean includeEvent,
boolean includeValue, boolean includeGauge) {
StatsdConfig.Builder config = StatsdConfig.newBuilder()
.setId(CONFIG_ID);
if (placebo) {
replication = 0; // Config will be empty, aside from a name.
}
int numMetrics = 0;
for (int i = 0; i < replication; i++) {
// metrics
if (includeEvent) {
for (EventMetric metric : mTemplate.getEventMetricList()) {
addEventMetric(metric, i, config);
numMetrics++;
}
}
if (includeCount) {
for (CountMetric metric : mTemplate.getCountMetricList()) {
addCountMetric(metric, i, bucket, config);
numMetrics++;
}
}
if (includeDuration) {
for (DurationMetric metric : mTemplate.getDurationMetricList()) {
addDurationMetric(metric, i, bucket, config);
numMetrics++;
}
}
if (includeGauge) {
for (GaugeMetric metric : mTemplate.getGaugeMetricList()) {
addGaugeMetric(metric, i, bucket, config);
numMetrics++;
}
}
if (includeValue) {
for (ValueMetric metric : mTemplate.getValueMetricList()) {
addValueMetric(metric, i, bucket, config);
numMetrics++;
}
}
// predicates
for (Predicate predicate : mTemplate.getPredicateList()) {
addPredicate(predicate, i, config);
}
// matchers
for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
addMatcher(matcher, i, config);
}
}
Log.d(TAG, "Loadtest config is : " + config.build());
Log.d(TAG, "Generated config has " + numMetrics + " metrics");
return new ConfigMetadata(config.build().toByteArray(), numMetrics);
}
/**
* Creates {@link MetricConditionLink}s that are identical to the one passed to this method,
* except that the names are appended with the provided suffix.
*/
private List<MetricConditionLink> getLinks(
List<MetricConditionLink> links, int suffix) {
List<MetricConditionLink> newLinks = new ArrayList();
for (MetricConditionLink link : links) {
newLinks.add(link.toBuilder()
.setCondition(link.getCondition() + suffix)
.build());
}
return newLinks;
}
/**
* Creates an {@link EventMetric} based on the template. Makes sure that all names are appended
* with the provided suffix. Then adds that metric to the config.
*/
private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
EventMetric.Builder metric = template.toBuilder()
.setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
}
if (template.getLinksCount() > 0) {
List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
metric.clearLinks();
metric.addAllLinks(links);
}
config.addEventMetric(metric);
}
/**
* Creates a {@link CountMetric} based on the template. Makes sure that all names are appended
* with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
*/
private void addCountMetric(CountMetric template, int suffix, TimeUnit bucket,
StatsdConfig.Builder config) {
CountMetric.Builder metric = template.toBuilder()
.setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
}
if (template.getLinksCount() > 0) {
List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
metric.clearLinks();
metric.addAllLinks(links);
}
metric.setBucket(bucket);
config.addCountMetric(metric);
}
/**
* Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended
* with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
*/
private void addDurationMetric(DurationMetric template, int suffix, TimeUnit bucket,
StatsdConfig.Builder config) {
DurationMetric.Builder metric = template.toBuilder()
.setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
}
if (template.getLinksCount() > 0) {
List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
metric.clearLinks();
metric.addAllLinks(links);
}
metric.setBucket(bucket);
config.addDurationMetric(metric);
}
/**
* Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended
* with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
*/
private void addGaugeMetric(GaugeMetric template, int suffix, TimeUnit bucket,
StatsdConfig.Builder config) {
GaugeMetric.Builder metric = template.toBuilder()
.setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
}
if (template.getLinksCount() > 0) {
List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
metric.clearLinks();
metric.addAllLinks(links);
}
metric.setBucket(bucket);
config.addGaugeMetric(metric);
}
/**
* Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended
* with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
*/
private void addValueMetric(ValueMetric template, int suffix, TimeUnit bucket,
StatsdConfig.Builder config) {
ValueMetric.Builder metric = template.toBuilder()
.setId(template.getId() + suffix)
.setWhat(template.getWhat() + suffix);
if (template.hasCondition()) {
metric.setCondition(template.getCondition() + suffix);
}
if (template.getLinksCount() > 0) {
List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
metric.clearLinks();
metric.addAllLinks(links);
}
metric.setBucket(bucket);
config.addValueMetric(metric);
}
/**
* Creates a {@link Predicate} based on the template. Makes sure that all names
* are appended with the provided suffix. Then adds that predicate to the config.
*/
private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
Predicate.Builder predicate = template.toBuilder()
.setId(template.getId() + suffix);
if (template.hasCombination()) {
Predicate.Combination.Builder cb = template.getCombination().toBuilder()
.clearPredicate();
for (long child : template.getCombination().getPredicateList()) {
cb.addPredicate(child + suffix);
}
predicate.setCombination(cb.build());
}
if (template.hasSimplePredicate()) {
SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
.setStart(template.getSimplePredicate().getStart() + suffix)
.setStop(template.getSimplePredicate().getStop() + suffix);
if (template.getSimplePredicate().hasStopAll()) {
sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
}
predicate.setSimplePredicate(sc.build());
}
config.addPredicate(predicate);
}
/**
* Creates a {@link AtomMatcher} based on the template. Makes sure that all names
* are appended with the provided suffix. Then adds that matcher to the config.
*/
private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
AtomMatcher.Builder matcher = template.toBuilder()
.setId(template.getId() + suffix);
if (template.hasCombination()) {
AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
.clearMatcher();
for (long child : template.getCombination().getMatcherList()) {
cb.addMatcher(child + suffix);
}
matcher.setCombination(cb);
}
config.addAtomMatcher(matcher);
}
}

View File

@@ -1,169 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.text.format.DateFormat;
import com.android.os.StatsLog;
import java.util.List;
public class DisplayProtoUtils {
private static final int MAX_NUM_METRICS_TO_DISPLAY = 10;
public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
sb.append("******************** Report ********************\n");
if (reports.hasConfigKey()) {
sb.append("ConfigKey: ");
com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
.append("\n");
}
int numMetrics = 0;
for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
append("\n");
sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
numMetrics++;
if (numMetrics > MAX_NUM_METRICS_TO_DISPLAY) {
sb.append("... output truncated\n");
sb.append("************************************************");
return;
}
sb.append("\n");
sb.append("metric id: ").append(log.getMetricId()).append("\n");
switch (log.getDataCase()) {
case DURATION_METRICS:
sb.append("Duration metric data\n");
displayDurationMetricData(sb, log);
break;
case EVENT_METRICS:
sb.append("Event metric data\n");
displayEventMetricData(sb, log);
break;
case COUNT_METRICS:
sb.append("Count metric data\n");
displayCountMetricData(sb, log);
break;
case GAUGE_METRICS:
sb.append("Gauge metric data\n");
displayGaugeMetricData(sb, log);
break;
case VALUE_METRICS:
sb.append("Value metric data\n");
displayValueMetricData(sb, log);
break;
case DATA_NOT_SET:
sb.append("No metric data\n");
break;
}
}
}
sb.append("************************************************");
}
public static String getDateStr(long nanoSec) {
return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
}
private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
sb.append(dimensionValue.getField()).append(":");
if (dimensionValue.hasValueBool()) {
sb.append(dimensionValue.getValueBool());
} else if (dimensionValue.hasValueFloat()) {
sb.append(dimensionValue.getValueFloat());
} else if (dimensionValue.hasValueInt()) {
sb.append(dimensionValue.getValueInt());
} else if (dimensionValue.hasValueStr()) {
sb.append(dimensionValue.getValueStr());
} else if (dimensionValue.hasValueTuple()) {
sb.append("{");
for (StatsLog.DimensionsValue child :
dimensionValue.getValueTuple().getDimensionsValueList()) {
displayDimension(sb, child);
}
sb.append("}");
}
sb.append(" ");
}
public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
= log.getDurationMetrics();
sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
sb.append("dimension_in_what: ");
displayDimension(sb, duration.getDimensionsInWhat());
sb.append("\n");
if (duration.hasDimensionsInCondition()) {
sb.append("dimension_in_condition: ");
displayDimension(sb, duration.getDimensionsInCondition());
sb.append("\n");
}
for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
.append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getDurationNanos()).append(" ns\n");
}
}
}
public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
= log.getCountMetrics();
sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
sb.append("dimension_in_what: ");
displayDimension(sb, count.getDimensionsInWhat());
sb.append("\n");
if (count.hasDimensionsInCondition()) {
sb.append("dimension_in_condition: ");
displayDimension(sb, count.getDimensionsInCondition());
sb.append("\n");
}
for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
.append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getCount()).append("\n");
}
}
}
public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
sb.append("Display me!");
}
public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
sb.append("Display me!");
}
}

View File

@@ -1,756 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.StatsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.IStatsManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.StatsLog;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.view.MotionEvent;
import android.view.View.OnFocusChangeListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.android.os.StatsLog.ConfigMetricsReport;
import com.android.os.StatsLog.ConfigMetricsReportList;
import com.android.os.StatsLog.StatsdStatsReport;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Runs a load test for statsd.
* How it works:
* <ul>
* <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
* <li> Periodically logs certain atoms into logd.
* <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
* in battery Historian.
* </ul>
* The load depends on how demanding the config is, as well as how frequently atoms are pushsed
* to logd. Those are all controlled by 4 adjustable parameters:
* <ul>
* <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
* <li> The bucket size controls the time-bucketing the aggregate metrics.
* <li> The period parameter controls how frequently atoms are pushed to logd.
* <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
* </ul>
*/
public class LoadtestActivity extends Activity implements AdapterView.OnItemSelectedListener {
private static final String TAG = "loadtest.LoadtestActivity";
public static final String TYPE = "type";
private static final String PUSH_ALARM = "push_alarm";
public static final String PERF_ALARM = "perf_alarm";
private static final String SET_REPLICATION = "set_replication";
private static final String REPLICATION = "replication";
private static final String START = "start";
private static final String STOP = "stop";
private static final Map<String, TimeUnit> TIME_UNIT_MAP = initializeTimeUnitMap();
private static final List<String> TIME_UNIT_LABELS = initializeTimeUnitLabels();
public final static class PusherAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent activityIntent = new Intent(context, LoadtestActivity.class);
activityIntent.putExtra(TYPE, PUSH_ALARM);
context.startActivity(activityIntent);
}
}
public final static class StopperAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent activityIntent = new Intent(context, LoadtestActivity.class);
activityIntent.putExtra(TYPE, STOP);
context.startActivity(activityIntent);
}
}
private static Map<String, TimeUnit> initializeTimeUnitMap() {
Map<String, TimeUnit> labels = new HashMap();
labels.put("1m", TimeUnit.ONE_MINUTE);
labels.put("5m", TimeUnit.FIVE_MINUTES);
labels.put("10m", TimeUnit.TEN_MINUTES);
labels.put("30m", TimeUnit.THIRTY_MINUTES);
labels.put("1h", TimeUnit.ONE_HOUR);
labels.put("3h", TimeUnit.THREE_HOURS);
labels.put("6h", TimeUnit.SIX_HOURS);
labels.put("12h", TimeUnit.TWELVE_HOURS);
labels.put("1d", TimeUnit.ONE_DAY);
labels.put("1s", TimeUnit.CTS);
return labels;
}
private static List<String> initializeTimeUnitLabels() {
List<String> labels = new ArrayList();
labels.add("1s");
labels.add("1m");
labels.add("5m");
labels.add("10m");
labels.add("30m");
labels.add("1h");
labels.add("3h");
labels.add("6h");
labels.add("12h");
labels.add("1d");
return labels;
}
private AlarmManager mAlarmMgr;
/**
* Used to periodically log atoms to logd.
*/
private PendingIntent mPushPendingIntent;
/**
* Used to end the loadtest.
*/
private PendingIntent mStopPendingIntent;
private Button mStartStop;
private EditText mReplicationText;
private Spinner mBucketSpinner;
private EditText mPeriodText;
private EditText mBurstText;
private EditText mDurationText;
private TextView mReportText;
private CheckBox mPlaceboCheckBox;
private CheckBox mCountMetricCheckBox;
private CheckBox mDurationMetricCheckBox;
private CheckBox mEventMetricCheckBox;
private CheckBox mValueMetricCheckBox;
private CheckBox mGaugeMetricCheckBox;
/**
* When the load test started.
*/
private long mStartedTimeMillis;
/**
* For measuring perf data.
*/
private PerfData mPerfData;
/**
* For communicating with statsd.
*/
private StatsManager mStatsManager;
private PowerManager mPowerManager;
private WakeLock mWakeLock;
/**
* If true, we only measure the effect of the loadtest infrastructure. No atom are pushed and
* the configuration is empty.
*/
private boolean mPlacebo;
/**
* Whether to include CountMetric in the config.
*/
private boolean mIncludeCountMetric;
/**
* Whether to include DurationMetric in the config.
*/
private boolean mIncludeDurationMetric;
/**
* Whether to include EventMetric in the config.
*/
private boolean mIncludeEventMetric;
/**
* Whether to include ValueMetric in the config.
*/
private boolean mIncludeValueMetric;
/**
* Whether to include GaugeMetric in the config.
*/
private boolean mIncludeGaugeMetric;
/**
* The burst size.
*/
private int mBurst;
/**
* The metrics replication.
*/
private int mReplication;
/**
* The period, in seconds, at which batches of atoms are pushed.
*/
private long mPeriodSecs;
/**
* The bucket size, in minutes, for aggregate metrics.
*/
private TimeUnit mBucket;
/**
* The duration, in minutes, of the loadtest.
*/
private long mDurationMins;
/**
* Whether the loadtest has started.
*/
private boolean mStarted = false;
/**
* Orchestrates the logging of pushed events into logd.
*/
private SequencePusher mPusher;
/**
* Generates statsd configs.
*/
private ConfigFactory mFactory;
/**
* For intra-minute periods.
*/
private final Handler mHandler = new Handler();
/**
* Number of metrics in the current config.
*/
private int mNumMetrics;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "Starting loadtest Activity");
setContentView(R.layout.activity_loadtest);
mReportText = (TextView) findViewById(R.id.report_text);
initBurst();
initReplication();
initBucket();
initPeriod();
initDuration();
initPlacebo();
initMetricWhitelist();
// Hide the keyboard outside edit texts.
findViewById(R.id.outside).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (getCurrentFocus() != null) {
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
return true;
}
});
mStartStop = findViewById(R.id.start_stop);
mStartStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mStarted) {
stopLoadtest();
} else {
startLoadtest();
}
}
});
mAlarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mStatsManager = (StatsManager) getSystemService("stats");
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mFactory = new ConfigFactory(this);
stopLoadtest();
mReportText.setText("");
}
@Override
public void onNewIntent(Intent intent) {
String type = intent.getStringExtra(TYPE);
if (type == null) {
return;
}
switch (type) {
case PERF_ALARM:
onPerfAlarm();
break;
case PUSH_ALARM:
onAlarm();
break;
case SET_REPLICATION:
if (intent.hasExtra(REPLICATION)) {
setReplication(intent.getIntExtra(REPLICATION, 0));
}
break;
case START:
startLoadtest();
break;
case STOP:
stopLoadtest();
break;
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
}
@Override
public void onDestroy() {
Log.d(TAG, "Destroying");
mPerfData.onDestroy();
stopLoadtest();
clearConfigs();
super.onDestroy();
}
@Nullable
public StatsdStatsReport getMetadata() {
if (!statsdRunning()) {
return null;
}
if (mStatsManager != null) {
byte[] data;
try {
data = mStatsManager.getStatsMetadata();
} catch (StatsManager.StatsUnavailableException e) {
Log.e(TAG, "Failed to get data from statsd", e);
return null;
}
if (data != null) {
StatsdStatsReport report = null;
boolean good = false;
try {
return StatsdStatsReport.parseFrom(data);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
Log.d(TAG, "Bad StatsdStatsReport");
}
}
}
return null;
}
@Nullable
public List<ConfigMetricsReport> getData() {
if (!statsdRunning()) {
return null;
}
if (mStatsManager != null) {
byte[] data;
try {
data = mStatsManager.getReports(ConfigFactory.CONFIG_ID);
} catch (StatsManager.StatsUnavailableException e) {
Log.e(TAG, "Failed to get data from statsd", e);
return null;
}
if (data != null) {
ConfigMetricsReportList reports = null;
try {
reports = ConfigMetricsReportList.parseFrom(data);
Log.d(TAG, "Num reports: " + reports.getReportsCount());
StringBuilder sb = new StringBuilder();
DisplayProtoUtils.displayLogReport(sb, reports);
Log.d(TAG, sb.toString());
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
Log.d(TAG, "Invalid data");
}
if (reports != null) {
return reports.getReportsList();
}
}
}
return null;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String item = parent.getItemAtPosition(position).toString();
mBucket = TIME_UNIT_MAP.get(item);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Another interface callback
}
private void onPerfAlarm() {
if (mPerfData != null) {
mPerfData.onAlarm(this);
}
// Piggy-back on that alarm to show the elapsed time.
long elapsedTimeMins = (long) Math.floor(
(SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
mReportText.setText("Loadtest in progress.\n"
+ "num metrics =" + mNumMetrics
+ "\nElapsed time = " + elapsedTimeMins + " min(s)");
}
private void onAlarm() {
Log.d(TAG, "ON ALARM");
// Set the next task.
scheduleNext();
// Do the work.
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StatsdLoadTest");
mWakeLock.acquire();
if (mPusher != null) {
mPusher.next();
}
mWakeLock.release();
mWakeLock = null;
}
/**
* Schedules the next cycle of pushing atoms into logd.
*/
private void scheduleNext() {
Intent intent = new Intent(this, PusherAlarmReceiver.class);
intent.putExtra(TYPE, PUSH_ALARM);
mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
}
private synchronized void startLoadtest() {
if (mStarted) {
return;
}
// Clean up the state.
stopLoadtest();
// Prepare to push a sequence of atoms to logd.
mPusher = new SequencePusher(mBurst, mPlacebo);
// Create a config and push it to statsd.
if (!setConfig(mFactory.getConfig(mReplication, mBucket, mPlacebo,
mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric,
mIncludeValueMetric, mIncludeGaugeMetric))) {
return;
}
// Remember to stop in the future.
Intent intent = new Intent(this, StopperAlarmReceiver.class);
intent.putExtra(TYPE, STOP);
mStopPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
// Log atoms.
scheduleNext();
// Start tracking performance.
mPerfData = new PerfData(this, mPlacebo, mReplication, mBucket, mPeriodSecs, mBurst,
mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
mIncludeGaugeMetric);
mPerfData.startRecording(this);
mReportText.setText("Loadtest in progress.\nnum metrics =" + mNumMetrics);
mStartedTimeMillis = SystemClock.elapsedRealtime();
updateStarted(true);
}
private synchronized void stopLoadtest() {
if (mPushPendingIntent != null) {
Log.d(TAG, "Canceling pre-existing push alarm");
mAlarmMgr.cancel(mPushPendingIntent);
mPushPendingIntent = null;
}
if (mStopPendingIntent != null) {
Log.d(TAG, "Canceling pre-existing stop alarm");
mAlarmMgr.cancel(mStopPendingIntent);
mStopPendingIntent = null;
}
if (mWakeLock != null) {
mWakeLock.release();
mWakeLock = null;
}
if (mPerfData != null) {
mPerfData.stopRecording(this);
mPerfData.onDestroy();
mPerfData = null;
}
// Obtain the latest data and display it.
getData();
long elapsedTimeMins = (long) Math.floor(
(SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
clearConfigs();
updateStarted(false);
}
private synchronized void updateStarted(boolean started) {
mStarted = started;
mStartStop.setBackgroundColor(started ?
Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
updateControlsEnabled();
}
private void updateControlsEnabled() {
mBurstText.setEnabled(!mPlacebo && !mStarted);
mReplicationText.setEnabled(!mPlacebo && !mStarted);
mPeriodText.setEnabled(!mStarted);
mBucketSpinner.setEnabled(!mPlacebo && !mStarted);
mDurationText.setEnabled(!mStarted);
mPlaceboCheckBox.setEnabled(!mStarted);
boolean enabled = !mStarted && !mPlaceboCheckBox.isChecked();
mCountMetricCheckBox.setEnabled(enabled);
mDurationMetricCheckBox.setEnabled(enabled);
mEventMetricCheckBox.setEnabled(enabled);
mValueMetricCheckBox.setEnabled(enabled);
mGaugeMetricCheckBox.setEnabled(enabled);
}
private boolean statsdRunning() {
if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
Log.d(TAG, "Statsd not running");
Toast.makeText(LoadtestActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
private int sanitizeInt(int val, int min, int max) {
if (val > max) {
val = max;
} else if (val < min) {
val = min;
}
return val;
}
private void clearConfigs() {
// TODO: Clear all configs instead of specific ones.
if (mStatsManager != null) {
if (mStarted) {
try {
mStatsManager.removeConfig(ConfigFactory.CONFIG_ID);
Log.d(TAG, "Removed loadtest statsd configs.");
} catch (StatsManager.StatsUnavailableException e) {
Log.e(TAG, "Failed to remove loadtest configs.", e);
}
}
}
}
private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
if (mStatsManager != null) {
try {
mStatsManager.addConfig(ConfigFactory.CONFIG_ID, configData.bytes);
mNumMetrics = configData.numMetrics;
Log.d(TAG, "Config pushed to statsd");
return true;
} catch (StatsManager.StatsUnavailableException | IllegalArgumentException e) {
Log.e(TAG, "Failed to push config to statsd", e);
}
}
return false;
}
private synchronized void setReplication(int replication) {
if (mStarted) {
return;
}
mReplicationText.setText("" + replication);
}
private synchronized void setPeriodSecs(long periodSecs) {
mPeriodSecs = periodSecs;
}
private synchronized void setBurst(int burst) {
mBurst = burst;
}
private synchronized void setDurationMins(long durationMins) {
mDurationMins = durationMins;
}
private void handleFocus(EditText editText) {
/*
editText.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus && editText.getText().toString().isEmpty()) {
editText.setText("-1", TextView.BufferType.EDITABLE);
}
}
});
*/
}
private void initBurst() {
mBurst = getResources().getInteger(R.integer.burst_default);
mBurstText = (EditText) findViewById(R.id.burst);
mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 1000) {
@Override
public void onNewValue(int newValue) {
setBurst(newValue);
}
});
handleFocus(mBurstText);
}
private void initReplication() {
mReplication = getResources().getInteger(R.integer.replication_default);
mReplicationText = (EditText) findViewById(R.id.replication);
mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 4096) {
@Override
public void onNewValue(int newValue) {
mReplication = newValue;
}
});
handleFocus(mReplicationText);
}
private void initBucket() {
String defaultValue = getResources().getString(R.string.bucket_default);
mBucket = TimeUnit.valueOf(defaultValue);
mBucketSpinner = (Spinner) findViewById(R.id.bucket_spinner);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
this, R.layout.spinner_item, TIME_UNIT_LABELS);
mBucketSpinner.setAdapter(dataAdapter);
mBucketSpinner.setOnItemSelectedListener(this);
for (String label : TIME_UNIT_MAP.keySet()) {
if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
mBucketSpinner.setSelection(dataAdapter.getPosition(label));
}
}
}
private void initPeriod() {
mPeriodSecs = getResources().getInteger(R.integer.period_default);
mPeriodText = (EditText) findViewById(R.id.period);
mPeriodText.addTextChangedListener(new NumericalWatcher(mPeriodText, 1, 60) {
@Override
public void onNewValue(int newValue) {
setPeriodSecs(newValue);
}
});
handleFocus(mPeriodText);
}
private void initDuration() {
mDurationMins = getResources().getInteger(R.integer.duration_default);
mDurationText = (EditText) findViewById(R.id.duration);
mDurationText.addTextChangedListener(new NumericalWatcher(mDurationText, 1, 24 * 60) {
@Override
public void onNewValue(int newValue) {
setDurationMins(newValue);
}
});
handleFocus(mDurationText);
}
private void initPlacebo() {
mPlaceboCheckBox = findViewById(R.id.placebo);
mPlacebo = false;
mPlaceboCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPlacebo = mPlaceboCheckBox.isChecked();
updateControlsEnabled();
}
});
}
private void initMetricWhitelist() {
mCountMetricCheckBox = findViewById(R.id.include_count);
mCountMetricCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mIncludeCountMetric = mCountMetricCheckBox.isChecked();
}
});
mDurationMetricCheckBox = findViewById(R.id.include_duration);
mDurationMetricCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
}
});
mEventMetricCheckBox = findViewById(R.id.include_event);
mEventMetricCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mIncludeEventMetric = mEventMetricCheckBox.isChecked();
}
});
mValueMetricCheckBox = findViewById(R.id.include_value);
mValueMetricCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mIncludeValueMetric = mValueMetricCheckBox.isChecked();
}
});
mGaugeMetricCheckBox = findViewById(R.id.include_gauge);
mGaugeMetricCheckBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
}
});
mIncludeCountMetric = mCountMetricCheckBox.isChecked();
mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
mIncludeEventMetric = mEventMetricCheckBox.isChecked();
mIncludeValueMetric = mValueMetricCheckBox.isChecked();
mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.util.Log;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** Parses PSS info from dumpsys meminfo */
public class MemInfoParser implements PerfParser {
private static final Pattern LINE_PATTERN =
Pattern.compile("\\s*(\\d*,*\\d*)K:\\s(\\S*)\\s\\.*");
private static final String PSS_BY_PROCESS = "Total PSS by process:";
private static final String TAG = "loadtest.MemInfoParser";
private boolean mPssStarted;
private boolean mPssEnded;
private final long mStartTimeMillis;
public MemInfoParser(long startTimeMillis) {
mStartTimeMillis = startTimeMillis;
}
@Override
@Nullable
public String parseLine(String line) {
if (mPssEnded) {
return null;
}
if (!mPssStarted) {
if (line.contains(PSS_BY_PROCESS)) {
mPssStarted = true;
}
return null;
}
if (line.isEmpty()) {
mPssEnded = true;
return null;
}
Matcher lineMatcher = LINE_PATTERN.matcher(line);
if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
if (lineMatcher.group(2).equals("statsd")) {
long timeDeltaMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
return timeDeltaMillis + "," + convertToPss(lineMatcher.group(1));
}
}
return null;
}
private String convertToPss(String input) {
return input.replace(",", "");
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.content.Context;
import android.os.SystemClock;
import android.util.Log;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
public class MemoryDataRecorder extends PerfDataRecorder {
private static final String TAG = "loadtest.MemoryDataDataRecorder";
private static final String DUMP_FILENAME = TAG + "_dump.tmp";
private long mStartTimeMillis;
private StringBuilder mSb;
public MemoryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
int burst, boolean includeCountMetric, boolean includeDurationMetric,
boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
}
@Override
public void startRecording(Context context) {
mStartTimeMillis = SystemClock.elapsedRealtime();
mSb = new StringBuilder();
}
@Override
public void onAlarm(Context context) {
runDumpsysStats(context, DUMP_FILENAME, "meminfo");
readDumpData(context, DUMP_FILENAME, new MemInfoParser(mStartTimeMillis), mSb);
}
@Override
public void stopRecording(Context context) {
writeData(context, "meminfo_", "time,pss", mSb);
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.TextView;
public abstract class NumericalWatcher implements TextWatcher {
private static final String TAG = "loadtest.NumericalWatcher";
private final TextView mTextView;
private final int mMin;
private final int mMax;
private int currentValue = -1;
public NumericalWatcher(TextView textView, int min, int max) {
mTextView = textView;
mMin = min;
mMax = max;
}
public abstract void onNewValue(int newValue);
@Override
final public void afterTextChanged(Editable editable) {
String s = mTextView.getText().toString();
if (s.isEmpty()) {
return;
}
int unsanitized = Integer.parseInt(s);
int newValue = sanitize(unsanitized);
if (currentValue != newValue || unsanitized != newValue) {
currentValue = newValue;
editable.clear();
editable.append(newValue + "");
}
onNewValue(newValue);
}
@Override
final public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
final public void onTextChanged(CharSequence s, int start, int before, int count) {}
private int sanitize(int val) {
if (val > mMax) {
val = mMax;
} else if (val < mMin) {
val = mMin;
}
return val;
}
}

View File

@@ -1,116 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;
import java.util.HashSet;
import java.util.Set;
/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
public class PerfData extends PerfDataRecorder {
private static final String TAG = "loadtest.PerfData";
/** Polling period for performance snapshots like memory. */
private static final long POLLING_PERIOD_MILLIS = 1 * 60 * 1000;
public final static class PerfAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent activityIntent = new Intent(context, LoadtestActivity.class);
activityIntent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
context.startActivity(activityIntent);
}
}
private AlarmManager mAlarmMgr;
/** Used to periodically poll some dumpsys data. */
private PendingIntent mPendingIntent;
private final Set<PerfDataRecorder> mRecorders;
public PerfData(LoadtestActivity loadtestActivity, boolean placebo, int replication,
TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
boolean includeGaugeMetric) {
super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
mRecorders = new HashSet();
mRecorders.add(new BatteryDataRecorder(placebo, replication, bucket, periodSecs, burst,
includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
includeGaugeMetric));
mRecorders.add(new MemoryDataRecorder(placebo, replication, bucket, periodSecs, burst,
includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
includeGaugeMetric));
mRecorders.add(new StatsdStatsRecorder(loadtestActivity, placebo, replication, bucket,
periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
includeValueMetric, includeGaugeMetric));
mRecorders.add(new ValidationRecorder(loadtestActivity, placebo, replication, bucket,
periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
includeValueMetric, includeGaugeMetric));
mAlarmMgr = (AlarmManager) loadtestActivity.getSystemService(Context.ALARM_SERVICE);
}
public void onDestroy() {
if (mPendingIntent != null) {
mAlarmMgr.cancel(mPendingIntent);
mPendingIntent = null;
}
}
@Override
public void startRecording(Context context) {
Intent intent = new Intent(context, PerfAlarmReceiver.class);
intent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
mAlarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, -1 /* now */,
POLLING_PERIOD_MILLIS, mPendingIntent);
for (PerfDataRecorder recorder : mRecorders) {
recorder.startRecording(context);
}
}
@Override
public void onAlarm(Context context) {
for (PerfDataRecorder recorder : mRecorders) {
recorder.onAlarm(context);
}
}
@Override
public void stopRecording(Context context) {
if (mPendingIntent != null) {
mAlarmMgr.cancel(mPendingIntent);
mPendingIntent = null;
}
for (PerfDataRecorder recorder : mRecorders) {
recorder.stopRecording(context);
}
}
}

View File

@@ -1,174 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.os.Debug;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public abstract class PerfDataRecorder {
private static final String TAG = "loadtest.PerfDataRecorder";
protected final String mTimeAsString;
protected final String mColumnSuffix;
protected PerfDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
int burst, boolean includeCountMetric, boolean includeDurationMetric,
boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
mTimeAsString = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
mColumnSuffix = getColumnSuffix(placebo, replication, bucket, periodSecs, burst,
includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
includeGaugeMetric);
}
/** Starts recording performance data. */
public abstract void startRecording(Context context);
/** Called periodically. For the recorder to sample data, if needed. */
public abstract void onAlarm(Context context);
/** Stops recording performance data, and writes it to disk. */
public abstract void stopRecording(Context context);
/** Runs the dumpsys command. */
protected void runDumpsysStats(Context context, String dumpFilename, String cmd,
String... args) {
boolean success = false;
// Call dumpsys Dump statistics to a file.
FileOutputStream fo = null;
try {
fo = context.openFileOutput(dumpFilename, Context.MODE_PRIVATE);
if (!Debug.dumpService(cmd, fo.getFD(), args)) {
Log.w(TAG, "Dumpsys failed.");
}
success = true;
} catch (IOException | SecurityException | NullPointerException e) {
// SecurityException may occur when trying to dump multi-user info.
// NPE can occur during dumpService (root cause unknown).
throw new RuntimeException(e);
} finally {
closeQuietly(fo);
}
}
/**
* Reads a text file and parses each line, one by one. The result of the parsing is stored
* in the passed {@link StringBuffer}.
*/
protected void readDumpData(Context context, String dumpFilename, PerfParser parser,
StringBuilder sb) {
FileInputStream fi = null;
BufferedReader br = null;
try {
fi = context.openFileInput(dumpFilename);
br = new BufferedReader(new InputStreamReader(fi));
String line = br.readLine();
while (line != null) {
String recordLine = parser.parseLine(line);
if (recordLine != null) {
sb.append(recordLine).append('\n');
}
line = br.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
closeQuietly(br);
}
}
/** Writes CSV data to a file. */
protected void writeData(Context context, String filePrefix, String columnPrefix,
StringBuilder sb) {
File dataFile = new File(getStorageDir(), filePrefix + mTimeAsString + ".csv");
FileWriter writer = null;
try {
writer = new FileWriter(dataFile);
writer.append(columnPrefix + mColumnSuffix + "\n");
writer.append(sb.toString());
writer.flush();
Log.d(TAG, "Finished writing data at " + dataFile.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
closeQuietly(writer);
}
}
/** Gets the suffix to use in the column name for perf data. */
private String getColumnSuffix(boolean placebo, int replication, TimeUnit bucket,
long periodSecs, int burst, boolean includeCountMetric, boolean includeDurationMetric,
boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
if (placebo) {
return "_placebo_p=" + periodSecs;
}
StringBuilder sb = new StringBuilder()
.append("_r=" + replication)
.append("_bkt=" + bucket)
.append("_p=" + periodSecs)
.append("_bst=" + burst)
.append("_m=");
if (includeCountMetric) {
sb.append("c");
}
if (includeEventMetric) {
sb.append("e");
}
if (includeDurationMetric) {
sb.append("d");
}
if (includeGaugeMetric) {
sb.append("g");
}
if (includeValueMetric) {
sb.append("v");
}
return sb.toString();
}
private File getStorageDir() {
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), "loadtest/" + mTimeAsString);
if (!file.mkdirs()) {
Log.e(TAG, "Directory not created");
}
return file;
}
private void closeQuietly(@Nullable Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException ignore) {
}
}
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.annotation.Nullable;
public interface PerfParser {
/**
* Parses one line of the dumpsys output, and returns a string to write to the data file,
* or null if no string should be written.
*/
@Nullable String parseLine(String line);
}

View File

@@ -1,165 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.util.Log;
import android.util.StatsLog;
import java.util.ArrayList;
import java.util.List;
/**
* Manages the pushing of atoms into logd for loadtesting.
* We rely on small number of pushed atoms, and a config with metrics based on those atoms.
* The atoms are:
* <ul>
* <li> BatteryLevelChanged - For EventMetric, CountMetric and GaugeMetric (no dimensions).
* <li> BleScanResultReceived - For CountMetric and ValueMetric, sliced by uid.
* <li> ChargingStateChanged - For DurationMetric (no dimension).
* <li> GpsScanStateChanged - For DurationMetric, sliced by uid.
* <li> ScreenStateChanged - For Conditions with no dimensions.
* <li> AudioStateChanged - For Conditions with dimensions (uid).
* </ul>
* The sequence is played over and over at a given frequency.
*/
public class SequencePusher {
private static final String TAG = "SequencePusher";
/** Some atoms are pushed in burst of {@code mBurst} events. */
private final int mBurst;
/** If this is true, we don't log anything in logd. */
private final boolean mPlacebo;
/** Current state in the automaton. */
private int mCursor = 0;
public SequencePusher(int burst, boolean placebo) {
mBurst = burst;
mPlacebo = placebo;
}
/**
* Pushes the next atom to logd.
* This follows a small automaton which makes the right events and conditions overlap:
* (0) Push a burst of BatteryLevelChanged atoms.
* (1) Push a burst of BleScanResultReceived atoms.
* (2) Push ChargingStateChanged with BATTERY_STATUS_CHARGING once.
* (3) Push a burst of GpsScanStateChanged atoms with ON, with a different uid each time.
* (4) Push ChargingStateChanged with BATTERY_STATUS_NOT_CHARGING once.
* (5) Push a burst GpsScanStateChanged atoms with OFF, with a different uid each time.
* (6) Push ScreenStateChanged with STATE_ON once.
* (7) Push a burst of AudioStateChanged with ON, with a different uid each time.
* (8) Repeat steps (0)-(5).
* (9) Push ScreenStateChanged with STATE_OFF once.
* (10) Push a burst of AudioStateChanged with OFF, with a different uid each time.
* and repeat.
*/
public void next() {
Log.d(TAG, "Next step: " + mCursor);
if (mPlacebo) {
return;
}
switch (mCursor) {
case 0:
case 8:
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, 50 + i /* battery_level */);
}
break;
case 1:
case 9:
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, i /* uid */,
100 /* num_of_results */);
}
break;
case 2:
case 10:
StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_CHARGING
/* charging_state */);
break;
case 3:
case 11:
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON /* state */);
}
break;
case 4:
case 12:
StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
/* charging_state */);
break;
case 5:
case 13:
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
}
break;
case 6:
StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON /* display_state */);
break;
case 7:
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
StatsLog.AUDIO_STATE_CHANGED__STATE__ON /* state */);
}
break;
case 14:
StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
break;
case 15:
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
}
break;
default:
}
mCursor++;
if (mCursor > 15) {
mCursor = 0;
}
}
/**
* Properly finishes in order to be close all conditions and durations.
*/
public void finish() {
// Screen goes back to off. This will ensure that conditions get back to false.
StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
}
// Stop charging, to ensure the corresponding durations are closed.
StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
/* charging_state */);
// Stop scanning GPS, to ensure the corresponding conditions get back to false.
for (int i = 0; i < mBurst; i++) {
StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.content.Context;
import com.android.os.StatsLog.StatsdStatsReport;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
public class StatsdStatsRecorder extends PerfDataRecorder {
private static final String TAG = "loadtest.StatsdStatsRecorder";
private final LoadtestActivity mLoadtestActivity;
public StatsdStatsRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
boolean includeGaugeMetric) {
super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
mLoadtestActivity = loadtestActivity;
}
@Override
public void startRecording(Context context) {
// Nothing to do.
}
@Override
public void onAlarm(Context context) {
// Nothing to do.
}
@Override
public void stopRecording(Context context) {
StatsdStatsReport metadata = mLoadtestActivity.getMetadata();
if (metadata != null) {
int numConfigs = metadata.getConfigStatsCount();
StringBuilder sb = new StringBuilder();
StatsdStatsReport.ConfigStats configStats = metadata.getConfigStats(numConfigs - 1);
sb.append("metric_count,")
.append(configStats.getMetricCount() + "\n")
.append("condition_count,")
.append(configStats.getConditionCount() + "\n")
.append("matcher_count,")
.append(configStats.getMatcherCount() + "\n");
writeData(context, "statsdstats_", "stat,value", sb);
}
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.statsd.loadtest;
import android.content.Context;
import android.util.Log;
import com.android.os.StatsLog.ConfigMetricsReport;
import com.android.os.StatsLog.EventMetricData;
import com.android.os.StatsLog.StatsLogReport;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Checks the correctness of the stats.
*/
public class ValidationRecorder extends PerfDataRecorder {
private static final String TAG = "loadtest.ValidationRecorder";
private final LoadtestActivity mLoadtestActivity;
public ValidationRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
boolean includeGaugeMetric) {
super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
mLoadtestActivity = loadtestActivity;
}
@Override
public void startRecording(Context context) {
// Nothing to do.
}
@Override
public void onAlarm(Context context) {
validateData();
}
@Override
public void stopRecording(Context context) {
validateData();
}
private void validateData() {
// The code below is commented out because it calls getData, which has the side-effect
// of clearing statsd's data buffer.
/*
List<ConfigMetricsReport> reports = mLoadtestActivity.getData();
if (reports != null) {
Log.d(TAG, "GOT DATA");
for (ConfigMetricsReport report : reports) {
for (StatsLogReport logReport : report.getMetricsList()) {
if (!logReport.hasMetricId()) {
Log.e(TAG, "Metric missing name.");
}
}
}
}
*/
}
private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
Log.d(TAG, "Validating " + logReport.getMetricId());
if (logReport.hasEventMetrics()) {
Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
Log.d(TAG, " Event : " + data.getAtom());
}
} else {
Log.d(TAG, "Metric is invalid");
}
}
private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
Log.d(TAG, "Validating " + logReport.getMetricId());
}
}