1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and limitations under the
13  * License.
14  *
15  */
16 
17 package com.android.benchmark.registry;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ActivityInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.content.res.Resources;
26 import android.content.res.TypedArray;
27 import android.content.res.XmlResourceParser;
28 import android.util.AttributeSet;
29 import android.util.SparseArray;
30 import android.util.Xml;
31 
32 import com.android.benchmark.R;
33 
34 import org.xmlpull.v1.XmlPullParser;
35 import org.xmlpull.v1.XmlPullParserException;
36 
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 /**
42  */
43 public class BenchmarkRegistry {
44 
45     /** Metadata key for benchmark XML data */
46     private static final String BENCHMARK_GROUP_META_KEY =
47             "com.android.benchmark.benchmark_group";
48 
49     /** Intent action specifying an activity that runs a single benchmark test. */
50     private static final String ACTION_BENCHMARK = "com.android.benchmark.ACTION_BENCHMARK";
51     public static final String EXTRA_ID = "com.android.benchmark.EXTRA_ID";
52 
53     private static final String TAG_BENCHMARK_GROUP = "com.android.benchmark.BenchmarkGroup";
54     private static final String TAG_BENCHMARK = "com.android.benchmark.Benchmark";
55 
56     private List<BenchmarkGroup> mGroups;
57 
58     private final Context mContext;
59 
BenchmarkRegistry(Context context)60     public BenchmarkRegistry(Context context) {
61         mContext = context;
62         mGroups = new ArrayList<>();
63         loadBenchmarks();
64     }
65 
getIntentFromInfo(ActivityInfo inf)66     private Intent getIntentFromInfo(ActivityInfo inf) {
67         Intent intent = new Intent();
68         intent.setClassName(inf.packageName, inf.name);
69         return intent;
70     }
71 
loadBenchmarks()72     public void loadBenchmarks() {
73         Intent intent = new Intent(ACTION_BENCHMARK);
74         intent.setPackage(mContext.getPackageName());
75 
76         PackageManager pm = mContext.getPackageManager();
77         List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
78                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
79 
80         for (ResolveInfo inf : resolveInfos) {
81             List<BenchmarkGroup> groups = parseBenchmarkGroup(inf.activityInfo);
82             if (groups != null) {
83                 mGroups.addAll(groups);
84             }
85         }
86     }
87 
seekToTag(XmlPullParser parser, String tag)88     private boolean seekToTag(XmlPullParser parser, String tag)
89             throws XmlPullParserException, IOException {
90         int eventType = parser.getEventType();
91         while (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_DOCUMENT) {
92             eventType = parser.next();
93         }
94         return eventType != XmlPullParser.END_DOCUMENT && tag.equals(parser.getName());
95     }
96 
getCategory(int category)97     @BenchmarkCategory int getCategory(int category) {
98         switch (category) {
99             case BenchmarkCategory.COMPUTE:
100                 return BenchmarkCategory.COMPUTE;
101             case BenchmarkCategory.UI:
102                 return BenchmarkCategory.UI;
103             default:
104                 return BenchmarkCategory.GENERIC;
105         }
106     }
107 
parseBenchmarkGroup(ActivityInfo activityInfo)108     private List<BenchmarkGroup> parseBenchmarkGroup(ActivityInfo activityInfo) {
109         PackageManager pm = mContext.getPackageManager();
110 
111         ComponentName componentName = new ComponentName(
112                 activityInfo.packageName, activityInfo.name);
113 
114         SparseArray<List<BenchmarkGroup.Benchmark>> benchmarks = new SparseArray<>();
115         String groupName, groupDescription;
116         try (XmlResourceParser parser = activityInfo.loadXmlMetaData(pm, BENCHMARK_GROUP_META_KEY)) {
117 
118             if (!seekToTag(parser, TAG_BENCHMARK_GROUP)) {
119                 return null;
120             }
121 
122             Resources res = pm.getResourcesForActivity(componentName);
123             AttributeSet attributeSet = Xml.asAttributeSet(parser);
124             TypedArray groupAttribs = res.obtainAttributes(attributeSet, R.styleable.BenchmarkGroup);
125 
126             groupName = groupAttribs.getString(R.styleable.BenchmarkGroup_name);
127             groupDescription = groupAttribs.getString(R.styleable.BenchmarkGroup_description);
128             groupAttribs.recycle();
129             parser.next();
130 
131             while (seekToTag(parser, TAG_BENCHMARK)) {
132                 TypedArray benchAttribs =
133                         res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Benchmark);
134                 int id = benchAttribs.getResourceId(R.styleable.Benchmark_id, -1);
135                 String testName = benchAttribs.getString(R.styleable.Benchmark_name);
136                 String testDescription = benchAttribs.getString(R.styleable.Benchmark_description);
137                 int testCategory = benchAttribs.getInt(R.styleable.Benchmark_category,
138                         BenchmarkCategory.GENERIC);
139                 int category = getCategory(testCategory);
140                 BenchmarkGroup.Benchmark benchmark = new BenchmarkGroup.Benchmark(
141                         id, testName, category, testDescription);
142                 List<BenchmarkGroup.Benchmark> benches = benchmarks.get(category);
143                 if (benches == null) {
144                     benches = new ArrayList<>();
145                     benchmarks.append(category, benches);
146                 }
147 
148                 benches.add(benchmark);
149 
150                 benchAttribs.recycle();
151                 parser.next();
152             }
153         } catch (PackageManager.NameNotFoundException | XmlPullParserException | IOException e) {
154             return null;
155         }
156 
157         List<BenchmarkGroup> result = new ArrayList<>();
158         Intent testIntent = getIntentFromInfo(activityInfo);
159         for (int i = 0; i < benchmarks.size(); i++) {
160             int cat = benchmarks.keyAt(i);
161             List<BenchmarkGroup.Benchmark> thisGroup = benchmarks.get(cat);
162             BenchmarkGroup.Benchmark[] benchmarkArray =
163                     new BenchmarkGroup.Benchmark[thisGroup.size()];
164             thisGroup.toArray(benchmarkArray);
165             result.add(new BenchmarkGroup(componentName,
166                     groupName + " - " + getCategoryString(cat), groupDescription, benchmarkArray,
167                     testIntent));
168         }
169 
170         return result;
171     }
172 
getGroupCount()173     public int getGroupCount() {
174         return mGroups.size();
175     }
176 
getBenchmarkCount(int benchmarkIndex)177     public int getBenchmarkCount(int benchmarkIndex) {
178         BenchmarkGroup group = getBenchmarkGroup(benchmarkIndex);
179         if (group != null) {
180             return group.getBenchmarks().length;
181         }
182         return 0;
183     }
184 
getBenchmarkGroup(int benchmarkIndex)185     public BenchmarkGroup getBenchmarkGroup(int benchmarkIndex) {
186         if (benchmarkIndex >= mGroups.size()) {
187             return null;
188         }
189 
190         return mGroups.get(benchmarkIndex);
191     }
192 
getCategoryString(int category)193     public static String getCategoryString(int category) {
194         switch (category) {
195             case BenchmarkCategory.UI:
196                 return "UI";
197             case BenchmarkCategory.COMPUTE:
198                 return "Compute";
199             case BenchmarkCategory.GENERIC:
200                 return "Generic";
201             default:
202                 return "";
203         }
204     }
205 
getBenchmarkName(Context context, int benchmarkId)206     public static String getBenchmarkName(Context context, int benchmarkId) {
207         switch (benchmarkId) {
208             case R.id.benchmark_list_view_scroll:
209                 return context.getString(R.string.list_view_scroll_name);
210             case R.id.benchmark_image_list_view_scroll:
211                 return context.getString(R.string.image_list_view_scroll_name);
212             case R.id.benchmark_shadow_grid:
213                 return context.getString(R.string.shadow_grid_name);
214             case R.id.benchmark_text_high_hitrate:
215                 return context.getString(R.string.text_high_hitrate_name);
216             case R.id.benchmark_text_low_hitrate:
217                 return context.getString(R.string.text_low_hitrate_name);
218             case R.id.benchmark_edit_text_input:
219                 return context.getString(R.string.edit_text_input_name);
220             case R.id.benchmark_memory_bandwidth:
221                 return context.getString(R.string.memory_bandwidth_name);
222             case R.id.benchmark_memory_latency:
223                 return context.getString(R.string.memory_latency_name);
224             case R.id.benchmark_power_management:
225                 return context.getString(R.string.power_management_name);
226             case R.id.benchmark_cpu_heat_soak:
227                 return context.getString(R.string.cpu_heat_soak_name);
228             case R.id.benchmark_cpu_gflops:
229                 return context.getString(R.string.cpu_gflops_name);
230             case R.id.benchmark_overdraw:
231                 return context.getString(R.string.overdraw_name);
232             case R.id.benchmark_bitmap_upload:
233                 return context.getString(R.string.bitmap_upload_name);
234             default:
235                 return "Some Benchmark";
236         }
237     }
238 }
239