1#!/usr/bin/env python3
2#
3# Copyright (C) 2021 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import os
18import time
19
20from simpleperf_utils import log_info, remove
21from . test_utils import TestBase, TestHelper
22
23
24class TestApiProfiler(TestBase):
25    def run_api_test(self, package_name, apk_name, expected_reports, min_android_version):
26        adb = TestHelper.adb
27        if TestHelper.android_version < ord(min_android_version) - ord('L') + 5:
28            log_info('skip this test on Android < %s.' % min_android_version)
29            return
30        # step 1: Prepare profiling.
31        self.run_cmd(['api_profiler.py', 'prepare'])
32        # step 2: Install and run the app.
33        apk_path = TestHelper.testdata_path(apk_name)
34        adb.run(['uninstall', package_name])
35        adb.check_run(['install', '-t', apk_path])
36        # Without sleep, the activity may be killed by post install intent ACTION_PACKAGE_CHANGED.
37        time.sleep(3)
38        adb.check_run(['shell', 'am', 'start', '-n', package_name + '/.MainActivity'])
39        # step 3: Wait until the app exits.
40        time.sleep(4)
41        while True:
42            result = adb.run(['shell', 'pidof', package_name])
43            if not result:
44                break
45            time.sleep(1)
46        # step 4: Collect recording data.
47        remove('simpleperf_data')
48        self.run_cmd(['api_profiler.py', 'collect', '-p', package_name, '-o', 'simpleperf_data'])
49        # step 5: Check recording data.
50        names = os.listdir('simpleperf_data')
51        self.assertGreater(len(names), 0)
52        for name in names:
53            path = os.path.join('simpleperf_data', name)
54            remove('report.txt')
55            self.run_cmd(['report.py', '-g', '-o', 'report.txt', '-i', path])
56            self.check_strings_in_file('report.txt', expected_reports)
57        # step 6: Clean up.
58        adb.check_run(['uninstall', package_name])
59
60    def run_cpp_api_test(self, apk_name, min_android_version):
61        self.run_api_test('simpleperf.demo.cpp_api', apk_name, ['BusyThreadFunc'],
62                          min_android_version)
63
64    def test_cpp_api_on_a_debuggable_app_targeting_prev_q(self):
65        # The source code of the apk is in simpleperf/demo/CppApi (with a small change to exit
66        # after recording).
67        self.run_cpp_api_test('cpp_api-debug_prev_Q.apk', 'N')
68
69    def test_cpp_api_on_a_debuggable_app_targeting_q(self):
70        self.run_cpp_api_test('cpp_api-debug_Q.apk', 'N')
71
72    def test_cpp_api_on_a_profileable_app_targeting_prev_q(self):
73        # a release apk with <profileable android:shell="true" />
74        self.run_cpp_api_test('cpp_api-profile_prev_Q.apk', 'Q')
75
76    def test_cpp_api_on_a_profileable_app_targeting_q(self):
77        self.run_cpp_api_test('cpp_api-profile_Q.apk', 'Q')
78
79    def run_java_api_test(self, apk_name, min_android_version):
80        self.run_api_test('simpleperf.demo.java_api', apk_name,
81                          ['simpleperf.demo.java_api.MainActivity', 'java.lang.Thread.run'],
82                          min_android_version)
83
84    def test_java_api_on_a_debuggable_app_targeting_prev_q(self):
85        # The source code of the apk is in simpleperf/demo/JavaApi (with a small change to exit
86        # after recording).
87        self.run_java_api_test('java_api-debug_prev_Q.apk', 'P')
88
89    def test_java_api_on_a_debuggable_app_targeting_q(self):
90        self.run_java_api_test('java_api-debug_Q.apk', 'P')
91
92    def test_java_api_on_a_profileable_app_targeting_prev_q(self):
93        # a release apk with <profileable android:shell="true" />
94        self.run_java_api_test('java_api-profile_prev_Q.apk', 'Q')
95
96    def test_java_api_on_a_profileable_app_targeting_q(self):
97        self.run_java_api_test('java_api-profile_Q.apk', 'Q')
98