summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:18:09 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:18:09 +0000
commit8a1a29ec3eca70431c9d2889c1c6be2ad4762ca2 (patch)
treed84b28d350017c324faceae3d10ccecfcbaa8ec8
parent6a9029542ce465b65f12221bdb6c9b74cec3252f (diff)
parentbde7153521922a2494889f496d2bd394e5708d81 (diff)
downloadextras-android10-mainline-resolv-release.tar.gz
Snap for 6001391 from bde7153521922a2494889f496d2bd394e5708d81 to qt-aml-resolv-releaseandroid-mainline-10.0.0_r8android10-mainline-resolv-release
Change-Id: I638cbefe9e344376c4cb155dda39f8459f5ab040
l---------libfscrypt/.clang-format1
-rw-r--r--libfscrypt/fscrypt.cpp269
-rw-r--r--libfscrypt/include/fscrypt/fscrypt.h40
-rw-r--r--libfscrypt/tests/Android.bp33
-rw-r--r--libfscrypt/tests/fscrypt_test.cpp138
-rw-r--r--libjsonpb/verify/test.cpp2
-rw-r--r--libperfmgr/tools/ConfigVerifier.cc17
-rw-r--r--simpleperf/JITDebugReader.cpp63
-rw-r--r--simpleperf/JITDebugReader.h4
-rw-r--r--simpleperf/cmd_record_test.cpp23
-rw-r--r--simpleperf/command.cpp5
-rw-r--r--simpleperf/event_selection_set.cpp5
-rwxr-xr-xsimpleperf/scripts/bin/android/arm/simpleperfbin2572060 -> 2571732 bytes
-rwxr-xr-xsimpleperf/scripts/bin/android/arm64/simpleperfbin3515984 -> 3520480 bytes
-rwxr-xr-xsimpleperf/scripts/bin/android/x86/simpleperfbin4256372 -> 4261104 bytes
-rwxr-xr-xsimpleperf/scripts/bin/android/x86_64/simpleperfbin4172272 -> 4172872 bytes
-rwxr-xr-xsimpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylibbin6273920 -> 6274128 bytes
-rwxr-xr-xsimpleperf/scripts/bin/darwin/x86_64/simpleperfbin7765332 -> 7779556 bytes
-rwxr-xr-xsimpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.sobin4986456 -> 4978264 bytes
-rwxr-xr-xsimpleperf/scripts/bin/linux/x86_64/simpleperfbin6224008 -> 6224008 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86/libsimpleperf_report.dllbin3894784 -> 3943424 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86/libwinpthread-1.dllbin211018 -> 231082 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86/simpleperf.exebin3834368 -> 3878912 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dllbin4183040 -> 4185600 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dllbin550120 -> 570473 bytes
-rwxr-xr-xsimpleperf/scripts/bin/windows/x86_64/simpleperf.exebin4189184 -> 4191232 bytes
-rw-r--r--simpleperf/scripts/script_testdata/cpp_api-profile_Q.apkbin1308411 -> 5079732 bytes
-rw-r--r--simpleperf/scripts/script_testdata/cpp_api-profile_prev_Q.apkbin1329603 -> 5078484 bytes
-rwxr-xr-xsimpleperf/scripts/test.py370
-rw-r--r--simpleperf/scripts/utils.py1
30 files changed, 674 insertions, 297 deletions
diff --git a/libfscrypt/.clang-format b/libfscrypt/.clang-format
new file mode 120000
index 00000000..973b2fab
--- /dev/null
+++ b/libfscrypt/.clang-format
@@ -0,0 +1 @@
+../../../build/soong/scripts/system-clang-format \ No newline at end of file
diff --git a/libfscrypt/fscrypt.cpp b/libfscrypt/fscrypt.cpp
index 66a43200..b76f0b17 100644
--- a/libfscrypt/fscrypt.cpp
+++ b/libfscrypt/fscrypt.cpp
@@ -18,6 +18,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <asm/ioctl.h>
#include <cutils/properties.h>
@@ -32,6 +33,10 @@
#include <utils/misc.h>
#include <array>
+#include <string>
+#include <vector>
+
+using namespace std::string_literals;
// TODO: switch to <linux/fscrypt.h> once it's in Bionic
#ifndef FSCRYPT_POLICY_V1
@@ -67,7 +72,45 @@ struct fscrypt_policy_v2 {
#define HEX_LOOKUP "0123456789abcdef"
-#define MAX_KEY_REF_SIZE_HEX (2 * FSCRYPT_KEY_IDENTIFIER_SIZE + 1)
+struct ModeLookupEntry {
+ std::string name;
+ int id;
+};
+
+static const auto contents_modes = std::vector<ModeLookupEntry>{
+ {"aes-256-xts"s, FS_ENCRYPTION_MODE_AES_256_XTS},
+ {"software"s, FS_ENCRYPTION_MODE_AES_256_XTS},
+ {"adiantum"s, FS_ENCRYPTION_MODE_ADIANTUM},
+ {"ice"s, FS_ENCRYPTION_MODE_PRIVATE},
+};
+
+static const auto filenames_modes = std::vector<ModeLookupEntry>{
+ {"aes-256-cts"s, FS_ENCRYPTION_MODE_AES_256_CTS},
+ {"aes-256-heh"s, FS_ENCRYPTION_MODE_AES_256_HEH},
+ {"adiantum"s, FS_ENCRYPTION_MODE_ADIANTUM},
+};
+
+static bool LookupModeByName(const std::vector<struct ModeLookupEntry>& modes,
+ const std::string& name, int* result) {
+ for (const auto& e : modes) {
+ if (e.name == name) {
+ *result = e.id;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool LookupModeById(const std::vector<struct ModeLookupEntry>& modes, int id,
+ std::string* result) {
+ for (const auto& e : modes) {
+ if (e.id == id) {
+ *result = e.name;
+ return true;
+ }
+ }
+ return false;
+}
bool fscrypt_is_native() {
char value[PROPERTY_VALUE_MAX];
@@ -75,6 +118,9 @@ bool fscrypt_is_native() {
return !strcmp(value, "file");
}
+namespace android {
+namespace fscrypt {
+
static void log_ls(const char* dirname) {
std::array<const char*, 3> argv = {"ls", "-laZ", dirname};
int status = 0;
@@ -96,17 +142,85 @@ static void log_ls(const char* dirname) {
}
}
-static void keyrefstring(const char* key_raw_ref, size_t key_raw_ref_length, char* hex) {
- size_t j = 0;
- for (size_t i = 0; i < key_raw_ref_length; i++) {
- hex[j++] = HEX_LOOKUP[(key_raw_ref[i] & 0xF0) >> 4];
- hex[j++] = HEX_LOOKUP[key_raw_ref[i] & 0x0F];
+void BytesToHex(const std::string& bytes, std::string* hex) {
+ hex->clear();
+ for (char c : bytes) {
+ *hex += HEX_LOOKUP[(c & 0xF0) >> 4];
+ *hex += HEX_LOOKUP[c & 0x0F];
}
- hex[j] = '\0';
}
-static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode, int policy_version) {
- uint8_t flags = 0;
+static bool fscrypt_is_encrypted(int fd) {
+ fscrypt_policy_v1 policy;
+
+ // success => encrypted with v1 policy
+ // EINVAL => encrypted with v2 policy
+ // ENODATA => not encrypted
+ return ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) == 0 || errno == EINVAL;
+}
+
+bool OptionsToString(const EncryptionOptions& options, std::string* options_string) {
+ std::string contents_mode, filenames_mode;
+ if (!LookupModeById(contents_modes, options.contents_mode, &contents_mode)) {
+ return false;
+ }
+ if (!LookupModeById(filenames_modes, options.filenames_mode, &filenames_mode)) {
+ return false;
+ }
+ *options_string = contents_mode + ":" + filenames_mode + ":v" + std::to_string(options.version);
+ if ((options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64)) {
+ *options_string += "+inlinecrypt_optimized";
+ }
+ EncryptionOptions options_check;
+ if (!ParseOptions(*options_string, &options_check)) {
+ LOG(ERROR) << "Internal error serializing options as string: " << *options_string;
+ return false;
+ }
+ if (memcmp(&options, &options_check, sizeof(options_check)) != 0) {
+ LOG(ERROR) << "Internal error serializing options as string, round trip failed: "
+ << *options_string;
+ return false;
+ }
+ return true;
+}
+
+bool ParseOptions(const std::string& options_string, EncryptionOptions* options) {
+ memset(options, '\0', sizeof(*options));
+ auto parts = android::base::Split(options_string, ":");
+ if (parts.size() < 1 || parts.size() > 3) {
+ return false;
+ }
+ if (!LookupModeByName(contents_modes, parts[0], &options->contents_mode)) {
+ LOG(ERROR) << "Invalid file contents encryption mode: " << parts[0];
+ return false;
+ }
+ if (parts.size() >= 2) {
+ if (!LookupModeByName(filenames_modes, parts[1], &options->filenames_mode)) {
+ LOG(ERROR) << "Invalid file names encryption mode: " << parts[1];
+ return false;
+ }
+ } else if (options->contents_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
+ options->filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
+ } else {
+ options->filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
+ }
+ options->version = 1;
+ options->flags = 0;
+ if (parts.size() >= 3) {
+ auto flags = android::base::Split(parts[2], "+");
+ for (const auto& flag : flags) {
+ if (flag == "v1") {
+ options->version = 1;
+ } else if (flag == "v2") {
+ options->version = 2;
+ } else if (flag == "inlinecrypt_optimized") {
+ options->flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64;
+ } else {
+ LOG(ERROR) << "Unknown flag: " << flag;
+ return false;
+ }
+ }
+ }
// In the original setting of v1 policies and AES-256-CTS we used 4-byte
// padding of filenames, so we have to retain that for compatibility.
@@ -114,105 +228,77 @@ static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode, int polic
// For everything else, use 16-byte padding. This is more secure (it helps
// hide the length of filenames), and it makes the inputs evenly divisible
// into cipher blocks which is more efficient for encryption and decryption.
- if (policy_version == 1 && filenames_encryption_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
- flags |= FS_POLICY_FLAGS_PAD_4;
+ if (options->version == 1 && options->filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
+ options->flags |= FS_POLICY_FLAGS_PAD_4;
} else {
- flags |= FS_POLICY_FLAGS_PAD_16;
+ options->flags |= FS_POLICY_FLAGS_PAD_16;
}
// Use DIRECT_KEY for Adiantum, since it's much more efficient but just as
// secure since Android doesn't reuse the same master key for multiple
// encryption modes.
- if (filenames_encryption_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
- flags |= FS_POLICY_FLAG_DIRECT_KEY;
+ if (options->filenames_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
+ options->flags |= FS_POLICY_FLAG_DIRECT_KEY;
}
-
- return flags;
+ return true;
}
-static bool fscrypt_is_encrypted(int fd) {
- fscrypt_policy_v1 policy;
-
- // success => encrypted with v1 policy
- // EINVAL => encrypted with v2 policy
- // ENODATA => not encrypted
- return ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) == 0 || errno == EINVAL;
+static std::string PolicyDebugString(const EncryptionPolicy& policy) {
+ std::stringstream ss;
+ std::string ref_hex;
+ BytesToHex(policy.key_raw_ref, &ref_hex);
+ ss << ref_hex;
+ ss << " v" << policy.options.version;
+ ss << " modes " << policy.options.contents_mode << "/" << policy.options.filenames_mode;
+ ss << std::hex << " flags 0x" << policy.options.flags;
+ return ss.str();
}
-int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t key_raw_ref_length,
- const char* contents_encryption_mode,
- const char* filenames_encryption_mode, int policy_version) {
- int contents_mode = 0;
- int filenames_mode = 0;
-
- if (!strcmp(contents_encryption_mode, "software") ||
- !strcmp(contents_encryption_mode, "aes-256-xts")) {
- contents_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
- } else if (!strcmp(contents_encryption_mode, "adiantum")) {
- contents_mode = FS_ENCRYPTION_MODE_ADIANTUM;
- } else if (!strcmp(contents_encryption_mode, "ice")) {
- contents_mode = FS_ENCRYPTION_MODE_PRIVATE;
- } else {
- LOG(ERROR) << "Invalid file contents encryption mode: "
- << contents_encryption_mode;
- return -1;
- }
-
- if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
- filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
- } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
- filenames_mode = FS_ENCRYPTION_MODE_AES_256_HEH;
- } else if (!strcmp(filenames_encryption_mode, "adiantum")) {
- filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
- } else {
- LOG(ERROR) << "Invalid file names encryption mode: "
- << filenames_encryption_mode;
- return -1;
- }
-
+bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory) {
union {
fscrypt_policy_v1 v1;
fscrypt_policy_v2 v2;
- } policy;
- memset(&policy, 0, sizeof(policy));
+ } kern_policy;
+ memset(&kern_policy, 0, sizeof(kern_policy));
- switch (policy_version) {
+ switch (policy.options.version) {
case 1:
- if (key_raw_ref_length != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
- LOG(ERROR) << "Invalid key ref length for v1 policy: " << key_raw_ref_length;
- return -1;
+ if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Invalid key descriptor length for v1 policy: "
+ << policy.key_raw_ref.size();
+ return false;
}
// Careful: FSCRYPT_POLICY_V1 is actually 0 in the API, so make sure
// to use it here instead of a literal 1.
- policy.v1.version = FSCRYPT_POLICY_V1;
- policy.v1.contents_encryption_mode = contents_mode;
- policy.v1.filenames_encryption_mode = filenames_mode;
- policy.v1.flags = fscrypt_get_policy_flags(filenames_mode, policy_version);
- memcpy(policy.v1.master_key_descriptor, key_raw_ref, FSCRYPT_KEY_DESCRIPTOR_SIZE);
+ kern_policy.v1.version = FSCRYPT_POLICY_V1;
+ kern_policy.v1.contents_encryption_mode = policy.options.contents_mode;
+ kern_policy.v1.filenames_encryption_mode = policy.options.filenames_mode;
+ kern_policy.v1.flags = policy.options.flags;
+ policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v1.master_key_descriptor),
+ FSCRYPT_KEY_DESCRIPTOR_SIZE);
break;
case 2:
- if (key_raw_ref_length != FSCRYPT_KEY_IDENTIFIER_SIZE) {
- LOG(ERROR) << "Invalid key ref length for v2 policy: " << key_raw_ref_length;
- return -1;
+ if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
+ LOG(ERROR) << "Invalid key identifier length for v2 policy: "
+ << policy.key_raw_ref.size();
+ return false;
}
- policy.v2.version = FSCRYPT_POLICY_V2;
- policy.v2.contents_encryption_mode = contents_mode;
- policy.v2.filenames_encryption_mode = filenames_mode;
- policy.v2.flags = fscrypt_get_policy_flags(filenames_mode, policy_version);
- memcpy(policy.v2.master_key_identifier, key_raw_ref, FSCRYPT_KEY_IDENTIFIER_SIZE);
+ kern_policy.v2.version = FSCRYPT_POLICY_V2;
+ kern_policy.v2.contents_encryption_mode = policy.options.contents_mode;
+ kern_policy.v2.filenames_encryption_mode = policy.options.filenames_mode;
+ kern_policy.v2.flags = policy.options.flags;
+ policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v2.master_key_identifier),
+ FSCRYPT_KEY_IDENTIFIER_SIZE);
break;
default:
- LOG(ERROR) << "Invalid encryption policy version: " << policy_version;
- return -1;
+ LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
+ return false;
}
- char ref[MAX_KEY_REF_SIZE_HEX];
- keyrefstring(key_raw_ref, key_raw_ref_length, ref);
-
- android::base::unique_fd fd(open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
+ android::base::unique_fd fd(open(directory.c_str(), O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
if (fd == -1) {
PLOG(ERROR) << "Failed to open directory " << directory;
- return -1;
+ return false;
}
bool already_encrypted = fscrypt_is_encrypted(fd);
@@ -220,7 +306,7 @@ int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t
// FS_IOC_SET_ENCRYPTION_POLICY will set the policy if the directory is
// unencrypted; otherwise it will verify that the existing policy matches.
// Setting the policy will fail if the directory is already nonempty.
- if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) != 0) {
+ if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &kern_policy) != 0) {
std::string reason;
switch (errno) {
case EEXIST:
@@ -230,20 +316,23 @@ int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t
reason = strerror(errno);
break;
}
- LOG(ERROR) << "Failed to set encryption policy of " << directory << " to " << ref
- << " modes " << contents_mode << "/" << filenames_mode << ": " << reason;
+ LOG(ERROR) << "Failed to set encryption policy of " << directory << " to "
+ << PolicyDebugString(policy) << ": " << reason;
if (errno == ENOTEMPTY) {
- log_ls(directory);
+ log_ls(directory.c_str());
}
- return -1;
+ return false;
}
if (already_encrypted) {
- LOG(INFO) << "Verified that " << directory << " has the encryption policy " << ref
- << " modes " << contents_mode << "/" << filenames_mode;
+ LOG(INFO) << "Verified that " << directory << " has the encryption policy "
+ << PolicyDebugString(policy);
} else {
- LOG(INFO) << "Encryption policy of " << directory << " set to " << ref << " modes "
- << contents_mode << "/" << filenames_mode;
+ LOG(INFO) << "Encryption policy of " << directory << " set to "
+ << PolicyDebugString(policy);
}
- return 0;
+ return true;
}
+
+} // namespace fscrypt
+} // namespace android
diff --git a/libfscrypt/include/fscrypt/fscrypt.h b/libfscrypt/include/fscrypt/fscrypt.h
index 13358bb7..2b809866 100644
--- a/libfscrypt/include/fscrypt/fscrypt.h
+++ b/libfscrypt/include/fscrypt/fscrypt.h
@@ -17,23 +17,45 @@
#ifndef _FSCRYPT_H_
#define _FSCRYPT_H_
-#include <sys/cdefs.h>
-#include <stdbool.h>
-#include <cutils/multiuser.h>
+#include <string>
-__BEGIN_DECLS
+// TODO: switch to <linux/fscrypt.h> once it's in Bionic
+#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08
bool fscrypt_is_native();
-int fscrypt_policy_ensure(const char* directory, const char* key_raw_ref, size_t key_raw_ref_length,
- const char* contents_encryption_mode,
- const char* filenames_encryption_mode, int policy_version);
-
static const char* fscrypt_unencrypted_folder = "/unencrypted";
static const char* fscrypt_key_ref = "/unencrypted/ref";
static const char* fscrypt_key_per_boot_ref = "/unencrypted/per_boot_ref";
static const char* fscrypt_key_mode = "/unencrypted/mode";
-__END_DECLS
+namespace android {
+namespace fscrypt {
+
+struct EncryptionOptions {
+ int version;
+ int contents_mode;
+ int filenames_mode;
+ int flags;
+
+ // Ensure that "version" is not valid on creation and so must be explicitly set
+ EncryptionOptions() : version(0) {}
+};
+
+struct EncryptionPolicy {
+ EncryptionOptions options;
+ std::string key_raw_ref;
+};
+
+void BytesToHex(const std::string& bytes, std::string* hex);
+
+bool OptionsToString(const EncryptionOptions& options, std::string* options_string);
+
+bool ParseOptions(const std::string& options_string, EncryptionOptions* options);
+
+bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory);
+
+} // namespace fscrypt
+} // namespace android
#endif // _FSCRYPT_H_
diff --git a/libfscrypt/tests/Android.bp b/libfscrypt/tests/Android.bp
new file mode 100644
index 00000000..985b425f
--- /dev/null
+++ b/libfscrypt/tests/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2019 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.
+
+cc_test {
+ name: "libfscrypt_unit_test",
+
+ shared_libs: [
+ "libbase",
+ ],
+ static_libs: [
+ "libfscrypt",
+ ],
+ srcs: [
+ "fscrypt_test.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/libfscrypt/tests/fscrypt_test.cpp b/libfscrypt/tests/fscrypt_test.cpp
new file mode 100644
index 00000000..677f0f22
--- /dev/null
+++ b/libfscrypt/tests/fscrypt_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <linux/fs.h>
+
+#include <fscrypt/fscrypt.h>
+
+#include <gtest/gtest.h>
+
+using namespace android::fscrypt;
+
+/* modes not supported by upstream kernel, so not in <linux/fs.h> */
+#define FS_ENCRYPTION_MODE_AES_256_HEH 126
+#define FS_ENCRYPTION_MODE_PRIVATE 127
+
+TEST(fscrypt, ParseOptions) {
+ EncryptionOptions options;
+ std::string options_string;
+
+ EXPECT_FALSE(ParseOptions("", &options));
+ EXPECT_FALSE(ParseOptions("blah", &options));
+
+ EXPECT_TRUE(ParseOptions("software", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("aes-256-xts", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("adiantum", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_16 | FS_POLICY_FLAG_DIRECT_KEY, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("adiantum:adiantum:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("adiantum:aes-256-heh", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_HEH, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_16, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("adiantum:aes-256-heh:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("ice", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("ice:aes-256-cts:v1", options_string);
+
+ EXPECT_FALSE(ParseOptions("ice:blah", &options));
+
+ EXPECT_TRUE(ParseOptions("ice:aes-256-cts", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("ice:aes-256-cts:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("ice:aes-256-heh", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_HEH, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_16, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("ice:aes-256-heh:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("ice:adiantum", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_PRIVATE, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_ADIANTUM, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_16 | FS_POLICY_FLAG_DIRECT_KEY, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("ice:adiantum:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v1", &options));
+ EXPECT_EQ(1, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_4, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v1", options_string);
+
+ EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v2", &options));
+ EXPECT_EQ(2, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_16, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v2", options_string);
+
+ EXPECT_TRUE(ParseOptions("aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", &options));
+ EXPECT_EQ(2, options.version);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_XTS, options.contents_mode);
+ EXPECT_EQ(FS_ENCRYPTION_MODE_AES_256_CTS, options.filenames_mode);
+ EXPECT_EQ(FS_POLICY_FLAGS_PAD_16 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64, options.flags);
+ EXPECT_TRUE(OptionsToString(options, &options_string));
+ EXPECT_EQ("aes-256-xts:aes-256-cts:v2+inlinecrypt_optimized", options_string);
+
+ EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:v2:", &options));
+ EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:v2:foo", &options));
+ EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:blah", &options));
+ EXPECT_FALSE(ParseOptions("aes-256-xts:aes-256-cts:vblah", &options));
+}
diff --git a/libjsonpb/verify/test.cpp b/libjsonpb/verify/test.cpp
index 31a734ad..cb98f47f 100644
--- a/libjsonpb/verify/test.cpp
+++ b/libjsonpb/verify/test.cpp
@@ -287,7 +287,7 @@ static const std::vector<ScalarTestErrorParam> gScalarTestErrorParams = {
{"{\"e\": 1}", "Should not allow integers for enums"},
};
-INSTANTIATE_TEST_SUITE_P(, ScalarTestError,
+INSTANTIATE_TEST_SUITE_P(Jsonpb, ScalarTestError,
::testing::ValuesIn(gScalarTestErrorParams));
int main(int argc, char** argv) {
diff --git a/libperfmgr/tools/ConfigVerifier.cc b/libperfmgr/tools/ConfigVerifier.cc
index a08fd006..2e25e950 100644
--- a/libperfmgr/tools/ConfigVerifier.cc
+++ b/libperfmgr/tools/ConfigVerifier.cc
@@ -44,23 +44,6 @@ class NodeVerifier : public HintManager {
return false;
}
- for (const auto& node : nodes) {
- std::vector<std::string> values = node->GetValues();
- std::string default_value = values[node->GetDefaultIndex()];
- // Always set to default first
- values.insert(values.begin(), default_value);
- // And reset to default after test
- values.push_back(default_value);
- for (const auto& value : values) {
- if (!android::base::WriteStringToFile(value, node->GetPath())) {
- LOG(ERROR) << "Failed to write to node: " << node->GetPath()
- << " with value: " << value;
- return false;
- }
- LOG(VERBOSE) << "Wrote to node: " << node->GetPath()
- << " with value: " << value;
- }
- }
return true;
}
diff --git a/simpleperf/JITDebugReader.cpp b/simpleperf/JITDebugReader.cpp
index 6de16aac..7ef3f25f 100644
--- a/simpleperf/JITDebugReader.cpp
+++ b/simpleperf/JITDebugReader.cpp
@@ -531,10 +531,10 @@ bool JITDebugReader::ReadNewCodeEntries(Process& process, const Descriptor& desc
}
if (descriptor.version == 2) {
if (process.is_64bit) {
- return ReadNewCodeEntriesImpl<JITCodeEntry64V2>(
+ return ReadNewCodeEntriesImplV2<JITCodeEntry64V2>(
process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
}
- return ReadNewCodeEntriesImpl<JITCodeEntry32V2>(
+ return ReadNewCodeEntriesImplV2<JITCodeEntry32V2>(
process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
}
return false;
@@ -548,6 +548,7 @@ bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor&
uint64_t current_entry_addr = descriptor.first_entry_addr;
uint64_t prev_entry_addr = 0u;
std::unordered_set<uint64_t> entry_addr_set;
+
for (size_t i = 0u; i < read_entry_limit && current_entry_addr != 0u; ++i) {
if (entry_addr_set.find(current_entry_addr) != entry_addr_set.end()) {
// We enter a loop, which means a broken linked list.
@@ -566,15 +567,54 @@ bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor&
// once we hit an entry with timestamp <= last_action_timestmap.
break;
}
- if (entry.symfile_size == 0) {
- continue;
+ if (entry.symfile_size > 0) {
+ CodeEntry code_entry;
+ code_entry.addr = current_entry_addr;
+ code_entry.symfile_addr = entry.symfile_addr;
+ code_entry.symfile_size = entry.symfile_size;
+ code_entry.timestamp = entry.register_timestamp;
+ new_code_entries->push_back(code_entry);
+ }
+ entry_addr_set.insert(current_entry_addr);
+ prev_entry_addr = current_entry_addr;
+ current_entry_addr = entry.next_addr;
+ }
+ return true;
+}
+
+// Temporary work around for patch "JIT mini-debug-info: Append packed entries towards end.", which
+// adds new entries at the end of the list and forces simpleperf to read the whole list.
+template <typename CodeEntryT>
+bool JITDebugReader::ReadNewCodeEntriesImplV2(Process& process, const Descriptor& descriptor,
+ uint64_t last_action_timestamp,
+ uint32_t /* read_entry_limit */,
+ std::vector<CodeEntry>* new_code_entries) {
+ uint64_t current_entry_addr = descriptor.first_entry_addr;
+ uint64_t prev_entry_addr = 0u;
+ std::unordered_set<uint64_t> entry_addr_set;
+ const size_t READ_ENTRY_LIMIT = 10000; // to avoid endless loop
+
+ for (size_t i = 0u; i < READ_ENTRY_LIMIT && current_entry_addr != 0u; ++i) {
+ if (entry_addr_set.find(current_entry_addr) != entry_addr_set.end()) {
+ // We enter a loop, which means a broken linked list.
+ return false;
+ }
+ CodeEntryT entry;
+ if (!ReadRemoteMem(process, current_entry_addr, sizeof(entry), &entry)) {
+ return false;
+ }
+ if (entry.prev_addr != prev_entry_addr || !entry.Valid()) {
+ // A broken linked list
+ return false;
+ }
+ if (entry.symfile_size > 0 && entry.register_timestamp > last_action_timestamp) {
+ CodeEntry code_entry;
+ code_entry.addr = current_entry_addr;
+ code_entry.symfile_addr = entry.symfile_addr;
+ code_entry.symfile_size = entry.symfile_size;
+ code_entry.timestamp = entry.register_timestamp;
+ new_code_entries->push_back(code_entry);
}
- CodeEntry code_entry;
- code_entry.addr = current_entry_addr;
- code_entry.symfile_addr = entry.symfile_addr;
- code_entry.symfile_size = entry.symfile_size;
- code_entry.timestamp = entry.register_timestamp;
- new_code_entries->push_back(code_entry);
entry_addr_set.insert(current_entry_addr);
prev_entry_addr = current_entry_addr;
current_entry_addr = entry.next_addr;
@@ -608,6 +648,9 @@ void JITDebugReader::ReadJITCodeDebugInfo(Process& process,
tmp_file->DoNotRemove();
}
auto callback = [&](const ElfFileSymbol& symbol) {
+ if (symbol.len == 0) { // Some arm labels can have zero length.
+ return;
+ }
LOG(VERBOSE) << "JITSymbol " << symbol.name << " at [" << std::hex << symbol.vaddr
<< " - " << (symbol.vaddr + symbol.len) << " with size " << symbol.len;
debug_info->emplace_back(process.pid, jit_entry.timestamp, symbol.vaddr, symbol.len,
diff --git a/simpleperf/JITDebugReader.h b/simpleperf/JITDebugReader.h
index 3be124e6..1a3b5e69 100644
--- a/simpleperf/JITDebugReader.h
+++ b/simpleperf/JITDebugReader.h
@@ -169,6 +169,10 @@ class JITDebugReader {
bool ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor,
uint64_t last_action_timestamp, uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries);
+ template <typename CodeEntryT>
+ bool ReadNewCodeEntriesImplV2(Process& process, const Descriptor& descriptor,
+ uint64_t last_action_timestamp, uint32_t read_entry_limit,
+ std::vector<CodeEntry>* new_code_entries);
void ReadJITCodeDebugInfo(Process& process, const std::vector<CodeEntry>& jit_entries,
std::vector<JITDebugInfo>* debug_info);
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 82f494f8..184f9359 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -747,7 +747,7 @@ TEST(record_cmd, cpu_percent_option) {
class RecordingAppHelper {
public:
bool InstallApk(const std::string& apk_path, const std::string& package_name) {
- if (Workload::RunCmd({"pm", "install", "-t", apk_path})) {
+ if (Workload::RunCmd({"pm", "install", "-t", "--abi", GetABI(), apk_path})) {
installed_packages_.emplace_back(package_name);
return true;
}
@@ -785,6 +785,20 @@ class RecordingAppHelper {
}
private:
+ const char* GetABI() {
+#if defined(__i386__)
+ return "x86";
+#elif defined(__x86_64__)
+ return "x86_64";
+#elif defined(__aarch64__)
+ return "arm64-v8a";
+#elif defined(__arm__)
+ return "armeabi-v7a";
+#else
+ #error "unrecognized ABI"
+#endif
+ }
+
std::vector<std::string> installed_packages_;
std::unique_ptr<Workload> app_start_proc_;
TemporaryFile perf_data_file_;
@@ -894,6 +908,13 @@ TEST(record_cmd, cs_etm_event) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm"}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
ASSERT_TRUE(reader);
+
+ // cs-etm uses sample period instead of sample freq.
+ ASSERT_EQ(reader->AttrSection().size(), 1u);
+ const perf_event_attr* attr = reader->AttrSection()[0].attr;
+ ASSERT_EQ(attr->freq, 0);
+ ASSERT_EQ(attr->sample_period, 1);
+
bool has_auxtrace_info = false;
bool has_auxtrace = false;
bool has_aux = false;
diff --git a/simpleperf/command.cpp b/simpleperf/command.cpp
index d751d610..e937e19b 100644
--- a/simpleperf/command.cpp
+++ b/simpleperf/command.cpp
@@ -24,7 +24,6 @@
#include <android-base/logging.h>
#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
-#include <android-base/quick_exit.h>
#include "utils.h"
@@ -177,9 +176,9 @@ bool RunSimpleperfCmd(int argc, char** argv) {
bool result = command->Run(args);
LOG(DEBUG) << "command '" << command_name << "' "
<< (result ? "finished successfully" : "failed");
- // Quick exit to avoid cost freeing memory and closing files.
+ // Quick exit to avoid the cost of freeing memory and closing files.
fflush(stdout);
fflush(stderr);
- android::base::quick_exit(result ? 0 : 1);
+ _Exit(result ? 0 : 1);
return result;
}
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index e1cba8cc..c7c7a38a 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -174,6 +174,11 @@ bool EventSelectionSet::BuildAndCheckEventSelection(const std::string& event_nam
if (event_type->event_type.type == PERF_TYPE_TRACEPOINT) {
selection->event_attr.freq = 0;
selection->event_attr.sample_period = DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT;
+ } else if (IsEtmEventType(event_type->event_type.type)) {
+ // ETM recording has no sample frequency to adjust. Using sample frequency only wastes time
+ // enabling/disabling etm devices. So don't adjust frequency by default.
+ selection->event_attr.freq = 0;
+ selection->event_attr.sample_period = 1;
} else {
selection->event_attr.freq = 1;
// Set default sample freq here may print msg "Adjust sample freq to max allowed sample
diff --git a/simpleperf/scripts/bin/android/arm/simpleperf b/simpleperf/scripts/bin/android/arm/simpleperf
index 81aa45c8..0bbb47fc 100755
--- a/simpleperf/scripts/bin/android/arm/simpleperf
+++ b/simpleperf/scripts/bin/android/arm/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/arm64/simpleperf b/simpleperf/scripts/bin/android/arm64/simpleperf
index 21fab083..72d505ce 100755
--- a/simpleperf/scripts/bin/android/arm64/simpleperf
+++ b/simpleperf/scripts/bin/android/arm64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/x86/simpleperf b/simpleperf/scripts/bin/android/x86/simpleperf
index afc8ae5d..8de146d3 100755
--- a/simpleperf/scripts/bin/android/x86/simpleperf
+++ b/simpleperf/scripts/bin/android/x86/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/x86_64/simpleperf b/simpleperf/scripts/bin/android/x86_64/simpleperf
index bb32c9f8..5cd23524 100755
--- a/simpleperf/scripts/bin/android/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/android/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib b/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
index cb0121c1..207eefe6 100755
--- a/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
+++ b/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86_64/simpleperf b/simpleperf/scripts/bin/darwin/x86_64/simpleperf
index 552cf259..c3f85c03 100755
--- a/simpleperf/scripts/bin/darwin/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/darwin/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so b/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
index 751a9ce1..fc48d068 100755
--- a/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
+++ b/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86_64/simpleperf b/simpleperf/scripts/bin/linux/x86_64/simpleperf
index 6a7b3a34..8ae69262 100755
--- a/simpleperf/scripts/bin/linux/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/linux/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll b/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll
index 5ef46de0..24e3129c 100755
--- a/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll
+++ b/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll b/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll
index 86de5d6e..a41127ab 100755
--- a/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll
+++ b/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86/simpleperf.exe b/simpleperf/scripts/bin/windows/x86/simpleperf.exe
index 2b26c7a9..c8e4e14a 100755
--- a/simpleperf/scripts/bin/windows/x86/simpleperf.exe
+++ b/simpleperf/scripts/bin/windows/x86/simpleperf.exe
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll b/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
index 7ba20159..a55350b3 100755
--- a/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
+++ b/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll b/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll
index ee5d7a3c..5a12ce3c 100755
--- a/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll
+++ b/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
index f5d10a4e..d221976a 100755
--- a/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
+++ b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
Binary files differ
diff --git a/simpleperf/scripts/script_testdata/cpp_api-profile_Q.apk b/simpleperf/scripts/script_testdata/cpp_api-profile_Q.apk
index b3f4e7d8..746b86cc 100644
--- a/simpleperf/scripts/script_testdata/cpp_api-profile_Q.apk
+++ b/simpleperf/scripts/script_testdata/cpp_api-profile_Q.apk
Binary files differ
diff --git a/simpleperf/scripts/script_testdata/cpp_api-profile_prev_Q.apk b/simpleperf/scripts/script_testdata/cpp_api-profile_prev_Q.apk
index 33d78806..9718824e 100644
--- a/simpleperf/scripts/script_testdata/cpp_api-profile_prev_Q.apk
+++ b/simpleperf/scripts/script_testdata/cpp_api-profile_prev_Q.apk
Binary files differ
diff --git a/simpleperf/scripts/test.py b/simpleperf/scripts/test.py
index 2adee0e0..b60d54d6 100755
--- a/simpleperf/scripts/test.py
+++ b/simpleperf/scripts/test.py
@@ -102,51 +102,97 @@ class TestLogger(object):
TEST_LOGGER = TestLogger()
-def get_device_features():
- adb = AdbHelper()
- adb.check_run_and_return_output(['push',
- 'bin/android/%s/simpleperf' % adb.get_device_arch(),
- '/data/local/tmp'])
- adb.check_run_and_return_output(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf'])
- return adb.check_run_and_return_output(['shell', '/data/local/tmp/simpleperf', 'list',
- '--show-features'])
-
-def is_trace_offcpu_supported():
- if not hasattr(is_trace_offcpu_supported, 'value'):
- is_trace_offcpu_supported.value = 'trace-offcpu' in get_device_features()
- return is_trace_offcpu_supported.value
-
-
-def android_version():
- """ Get Android version on device, like 7 is for Android N, 8 is for Android O."""
- if not hasattr(android_version, 'value'):
- android_version.value = AdbHelper().get_android_version()
- return android_version.value
-
-
-def build_testdata():
- """ Collect testdata from ../testdata and ../demo. """
- from_testdata_path = os.path.join('..', 'testdata')
- from_demo_path = os.path.join('..', 'demo')
- from_script_testdata_path = 'script_testdata'
- if (not os.path.isdir(from_testdata_path) or not os.path.isdir(from_demo_path) or
- not from_script_testdata_path):
- return
- copy_demo_list = ['SimpleperfExamplePureJava', 'SimpleperfExampleWithNative',
- 'SimpleperfExampleOfKotlin']
-
- testdata_path = "testdata"
- remove(testdata_path)
- shutil.copytree(from_testdata_path, testdata_path)
- for demo in copy_demo_list:
- shutil.copytree(os.path.join(from_demo_path, demo), os.path.join(testdata_path, demo))
- for f in os.listdir(from_script_testdata_path):
- shutil.copy(os.path.join(from_script_testdata_path, f), testdata_path)
+class TestHelper(object):
+ """ Keep global test info. """
+
+ def __init__(self):
+ self.python_version = 3 if is_python3() else 2
+ self.repeat_count = 0
+ self.script_dir = os.path.abspath(get_script_dir())
+ self.cur_dir = os.getcwd()
+ self.testdata_dir = os.path.join(self.cur_dir, 'testdata')
+ self.test_base_dir = self.get_test_base_dir(self.python_version)
+ self.adb = AdbHelper(enable_switch_to_root=True)
+ self.android_version = self.adb.get_android_version()
+ self.device_features = None
+ self.browser_option = []
+
+ def get_test_base_dir(self, python_version):
+ """ Return the dir of generated data for a python version. """
+ return os.path.join(self.cur_dir, 'test_python_%d' % python_version)
+
+ def testdata_path(self, testdata_name):
+ """ Return the path of a test data. """
+ return os.path.join(self.testdata_dir, testdata_name.replace('/', os.sep))
+
+ def test_dir(self, test_name):
+ """ Return the dir to run a test. """
+ return os.path.join(
+ self.test_base_dir, 'repeat_%d' % TEST_HELPER.repeat_count, test_name)
+
+ def script_path(self, script_name):
+ """ Return the dir of python scripts. """
+ return os.path.join(self.script_dir, script_name)
+
+ def get_device_features(self):
+ if self.device_features is None:
+ args = [sys.executable, self.script_path(
+ 'run_simpleperf_on_device.py'), 'list', '--show-features']
+ output = subprocess.check_output(args, stderr=TEST_LOGGER.log_fh)
+ output = bytes_to_str(output)
+ self.device_features = output.split()
+ return self.device_features
+
+ def is_trace_offcpu_supported(self):
+ return 'trace-offcpu' in self.get_device_features()
+
+ def build_testdata(self):
+ """ Collect testdata in self.testdata_dir.
+ In system/extras/simpleperf/scripts, testdata comes from:
+ <script_dir>/../testdata, <script_dir>/script_testdata, <script_dir>/../demo
+ In prebuilts/simpleperf, testdata comes from:
+ <script_dir>/testdata
+ """
+ if os.path.isdir(self.testdata_dir):
+ return # already built
+ os.makedirs(self.testdata_dir)
+
+ source_dirs = [os.path.join('..', 'testdata'), 'script_testdata',
+ os.path.join('..', 'demo'), 'testdata']
+ source_dirs = [os.path.join(self.script_dir, x) for x in source_dirs]
+ source_dirs = [x for x in source_dirs if os.path.isdir(x)]
+
+ for source_dir in source_dirs:
+ for name in os.listdir(source_dir):
+ source = os.path.join(source_dir, name)
+ target = os.path.join(self.testdata_dir, name)
+ if os.path.exists(target):
+ continue
+ if os.path.isfile(source):
+ shutil.copyfile(source, target)
+ elif os.path.isdir(source):
+ shutil.copytree(source, target)
+
+ def get_32bit_abi(self):
+ return self.adb.get_property('ro.product.cpu.abilist32').strip().split(',')[0]
+
+
+TEST_HELPER = TestHelper()
+
class TestBase(unittest.TestCase):
+ def setUp(self):
+ """ Run each test in a separate dir. """
+ self.test_dir = TEST_HELPER.test_dir('%s.%s' % (
+ self.__class__.__name__, self._testMethodName))
+ os.makedirs(self.test_dir)
+ os.chdir(self.test_dir)
+
def run_cmd(self, args, return_output=False):
+ if args[0] == 'report_html.py' or args[0] == INFERNO_SCRIPT:
+ args += TEST_HELPER.browser_option
if args[0].endswith('.py'):
- args = [sys.executable] + args
+ args = [sys.executable, TEST_HELPER.script_path(args[0])] + args[1:]
use_shell = args[0].endswith('.bat')
try:
if not return_output:
@@ -184,7 +230,7 @@ class TestExampleBase(TestBase):
@classmethod
def prepare(cls, example_name, package_name, activity_name, abi=None, adb_root=False):
cls.adb = AdbHelper(enable_switch_to_root=adb_root)
- cls.example_path = os.path.join("testdata", example_name)
+ cls.example_path = TEST_HELPER.testdata_path(example_name)
if not os.path.isdir(cls.example_path):
log_fatal("can't find " + cls.example_path)
for root, _, files in os.walk(cls.example_path):
@@ -195,64 +241,49 @@ class TestExampleBase(TestBase):
log_fatal("can't find app-profiling.apk under " + cls.example_path)
cls.package_name = package_name
cls.activity_name = activity_name
- cls.abi = "arm64"
- if abi and abi != "arm64" and abi.find("arm") != -1:
- cls.abi = "arm"
args = ["install", "-r"]
if abi:
args += ["--abi", abi]
args.append(cls.apk_path)
cls.adb.check_run(args)
cls.adb_root = adb_root
- cls.compiled = False
cls.has_perf_data_for_report = False
# On Android >= P (version 9), we can profile JITed and interpreted Java code.
# So only compile Java code on Android <= O (version 8).
- cls.use_compiled_java_code = android_version() <= 8
-
- def setUp(self):
- if self.id().find('TraceOffCpu') != -1 and not is_trace_offcpu_supported():
- self.skipTest('trace-offcpu is not supported on device')
- cls = self.__class__
- if not cls.has_perf_data_for_report:
- cls.has_perf_data_for_report = True
- self.run_app_profiler()
- shutil.copy('perf.data', 'perf.data_for_report')
- remove('binary_cache_for_report')
- shutil.copytree('binary_cache', 'binary_cache_for_report')
- else:
- shutil.copy('perf.data_for_report', 'perf.data')
- remove('binary_cache')
- shutil.copytree('binary_cache_for_report', 'binary_cache')
+ cls.use_compiled_java_code = TEST_HELPER.android_version <= 8
+ cls.testcase_dir = TEST_HELPER.test_dir(cls.__name__)
@classmethod
def tearDownClass(cls):
- if hasattr(cls, 'test_result') and cls.test_result and not cls.test_result.wasSuccessful():
- return
+ remove(cls.testcase_dir)
if hasattr(cls, 'package_name'):
cls.adb.check_run(["uninstall", cls.package_name])
- remove("binary_cache")
- remove("annotated_files")
- remove("perf.data")
- remove("report.txt")
- remove("pprof.profile")
- if cls.has_perf_data_for_report:
- cls.has_perf_data_for_report = False
- remove('perf.data_for_report')
- remove('binary_cache_for_report')
+
+ def setUp(self):
+ super(TestExampleBase, self).setUp()
+ if 'TraceOffCpu' in self.id() and not TEST_HELPER.is_trace_offcpu_supported():
+ self.skipTest('trace-offcpu is not supported on device')
+ # Use testcase_dir to share a common perf.data for reporting. So we don't need to
+ # generate it for each test.
+ if not os.path.isdir(self.testcase_dir):
+ os.makedirs(self.testcase_dir)
+ os.chdir(self.testcase_dir)
+ self.run_app_profiler(compile_java_code=self.use_compiled_java_code)
+ remove(self.test_dir)
+ shutil.copytree(self.testcase_dir, self.test_dir)
+ os.chdir(self.test_dir)
def run(self, result=None):
self.__class__.test_result = result
super(TestExampleBase, self).run(result)
def run_app_profiler(self, record_arg="-g --duration 10", build_binary_cache=True,
- start_activity=True):
+ start_activity=True, compile_java_code=False):
args = ['app_profiler.py', '--app', self.package_name, '-r', record_arg, '-o', 'perf.data']
if not build_binary_cache:
args.append("-nb")
- if self.use_compiled_java_code and not self.__class__.compiled:
+ if compile_java_code:
args.append('--compile_java_code')
- self.__class__.compiled = True
if start_activity:
args += ["-a", self.activity_name]
args += ["-lib", self.example_path]
@@ -384,7 +415,6 @@ class TestExampleBase(TestBase):
shutil.move('perf.data', 'perf2.data')
self.run_app_profiler(record_arg='-g -f 1000 --duration 3 -e task-clock:u')
self.run_cmd(['report_html.py', '-i', 'perf.data', 'perf2.data'])
- remove('perf2.data')
class TestExamplePureJava(TestExampleBase):
@@ -419,8 +449,8 @@ class TestExamplePureJava(TestExampleBase):
return
self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
time.sleep(1)
- args = [sys.executable, "app_profiler.py", "--app", self.package_name,
- "-r", "--duration 10000", "--disable_adb_root"]
+ args = [sys.executable, TEST_HELPER.script_path("app_profiler.py"),
+ "--app", self.package_name, "-r", "--duration 10000", "--disable_adb_root"]
subproc = subprocess.Popen(args)
time.sleep(3)
@@ -432,8 +462,9 @@ class TestExamplePureJava(TestExampleBase):
def test_app_profiler_stop_after_app_exit(self):
self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
time.sleep(1)
- subproc = subprocess.Popen([sys.executable, 'app_profiler.py', '--app', self.package_name,
- '-r', '--duration 10000', '--disable_adb_root'])
+ subproc = subprocess.Popen(
+ [sys.executable, TEST_HELPER.script_path('app_profiler.py'),
+ '--app', self.package_name, '-r', '--duration 10000', '--disable_adb_root'])
time.sleep(3)
self.adb.check_run(['shell', 'am', 'force-stop', self.package_name])
subproc.wait()
@@ -502,20 +533,15 @@ class TestExamplePureJava(TestExampleBase):
self.check_inferno_report_html(
[('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)],
"report2.html")
- remove("report2.html")
def test_inferno_in_another_dir(self):
test_dir = 'inferno_testdir'
- saved_dir = os.getcwd()
- remove(test_dir)
os.mkdir(test_dir)
os.chdir(test_dir)
- self.run_cmd(['python', os.path.join(saved_dir, 'app_profiler.py'),
- '--app', self.package_name, '-r', '-e task-clock:u -g --duration 3'])
+ self.run_cmd(['app_profiler.py', '--app', self.package_name,
+ '-r', '-e task-clock:u -g --duration 3'])
self.check_exist(filename="perf.data")
self.run_cmd([INFERNO_SCRIPT, "-sc"])
- os.chdir(saved_dir)
- remove(test_dir)
def test_report_html(self):
self.common_test_report_html()
@@ -711,32 +737,32 @@ class TestExampleWithNativeJniCall(TestExampleBase):
self.run_cmd([INFERNO_SCRIPT, "-sc"])
-class TestExampleWithNativeForceArm(TestExampleWithNative):
+class TestExampleWithNativeForce32Bit(TestExampleWithNative):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleWithNative",
"com.example.simpleperf.simpleperfexamplewithnative",
".MainActivity",
- abi="armeabi-v7a")
+ abi=TEST_HELPER.get_32bit_abi())
-class TestExampleWithNativeForceArmRoot(TestExampleWithNativeRoot):
+class TestExampleWithNativeRootForce32Bit(TestExampleWithNativeRoot):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleWithNative",
"com.example.simpleperf.simpleperfexamplewithnative",
".MainActivity",
- abi="armeabi-v7a",
+ abi=TEST_HELPER.get_32bit_abi(),
adb_root=False)
-class TestExampleWithNativeTraceOffCpuForceArm(TestExampleWithNativeTraceOffCpu):
+class TestExampleWithNativeTraceOffCpuForce32Bit(TestExampleWithNativeTraceOffCpu):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleWithNative",
"com.example.simpleperf.simpleperfexamplewithnative",
".SleepActivity",
- abi="armeabi-v7a")
+ abi=TEST_HELPER.get_32bit_abi())
class TestExampleOfKotlin(TestExampleBase):
@@ -855,8 +881,8 @@ class TestExampleOfKotlinTraceOffCpu(TestExampleBase):
class TestNativeProfiling(TestBase):
def setUp(self):
- self.adb = AdbHelper()
- self.is_rooted_device = self.adb.switch_to_root()
+ super(TestNativeProfiling, self).setUp()
+ self.is_rooted_device = TEST_HELPER.adb.switch_to_root()
def test_profile_cmd(self):
self.run_cmd(["app_profiler.py", "-cmd", "pm -l", "--disable_adb_root"])
@@ -873,7 +899,7 @@ class TestNativeProfiling(TestBase):
def test_profile_pids(self):
if not self.is_rooted_device:
return
- pid = int(self.adb.check_run_and_return_output(['shell', 'pidof', 'system_server']))
+ pid = int(TEST_HELPER.adb.check_run_and_return_output(['shell', 'pidof', 'system_server']))
self.run_cmd(['app_profiler.py', '--pid', str(pid), '-r', '--duration 1'])
self.run_cmd(['app_profiler.py', '--pid', str(pid), str(pid), '-r', '--duration 1'])
self.run_cmd(['app_profiler.py', '--tid', str(pid), '-r', '--duration 1'])
@@ -886,13 +912,15 @@ class TestNativeProfiling(TestBase):
self.run_cmd(['app_profiler.py', '--system_wide', '-r', '--duration 1'])
-class TestReportLib(unittest.TestCase):
+class TestReportLib(TestBase):
def setUp(self):
+ super(TestReportLib, self).setUp()
self.report_lib = ReportLib()
- self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_symbols.data'))
+ self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_symbols.data'))
def tearDown(self):
self.report_lib.Close()
+ super(TestReportLib, self).tearDown()
def test_build_id(self):
build_id = self.report_lib.GetBuildIdForPath('/data/t2')
@@ -926,7 +954,7 @@ class TestReportLib(unittest.TestCase):
self.assertTrue(found_sample)
def test_meta_info(self):
- self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_trace_offcpu.data'))
+ self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
meta_info = self.report_lib.MetaInfo()
self.assertTrue("simpleperf_version" in meta_info)
self.assertEqual(meta_info["system_wide_collection"], "false")
@@ -935,7 +963,7 @@ class TestReportLib(unittest.TestCase):
self.assertTrue("product_props" in meta_info)
def test_event_name_from_meta_info(self):
- self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_tracepoint_event.data'))
+ self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_tracepoint_event.data'))
event_names = set()
while self.report_lib.GetNextSample():
event_names.add(self.report_lib.GetEventOfCurrentSample().name)
@@ -943,13 +971,13 @@ class TestReportLib(unittest.TestCase):
self.assertTrue('cpu-cycles' in event_names)
def test_record_cmd(self):
- self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_trace_offcpu.data'))
+ self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
self.assertEqual(self.report_lib.GetRecordCmd(),
"/data/local/tmp/simpleperf record --trace-offcpu --duration 2 -g " +
"./simpleperf_runtest_run_and_sleep64")
def test_offcpu(self):
- self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_trace_offcpu.data'))
+ self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
total_period = 0
sleep_function_period = 0
sleep_function_name = "SleepFunction(unsigned long long)"
@@ -970,7 +998,7 @@ class TestReportLib(unittest.TestCase):
def test_show_art_frames(self):
def has_art_frame(report_lib):
- report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_interpreter_frames.data'))
+ report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_interpreter_frames.data'))
result = False
while report_lib.GetNextSample():
callchain = report_lib.GetCallChainOfCurrentSample()
@@ -993,7 +1021,7 @@ class TestReportLib(unittest.TestCase):
def test_merge_java_methods(self):
def parse_dso_names(report_lib):
dso_names = set()
- report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_interpreter_frames.data'))
+ report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_interpreter_frames.data'))
while report_lib.GetNextSample():
dso_names.add(report_lib.GetSymbolOfCurrentSample().dso_name)
callchain = report_lib.GetCallChainOfCurrentSample()
@@ -1016,7 +1044,7 @@ class TestReportLib(unittest.TestCase):
self.assertEqual(parse_dso_names(report_lib), (True, False))
def test_tracing_data(self):
- self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_tracepoint_event.data'))
+ self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_tracepoint_event.data'))
has_tracing_data = False
while self.report_lib.GetNextSample():
event = self.report_lib.GetEventOfCurrentSample()
@@ -1037,13 +1065,13 @@ class TestRunSimpleperfOnDevice(TestBase):
self.run_cmd(['run_simpleperf_on_device.py', 'list', '--show-features'])
-class TestTools(unittest.TestCase):
+class TestTools(TestBase):
def test_addr2nearestline(self):
self.run_addr2nearestline_test(True)
self.run_addr2nearestline_test(False)
def run_addr2nearestline_test(self, with_function_name):
- binary_cache_path = 'testdata'
+ binary_cache_path = TEST_HELPER.testdata_dir
test_map = {
'/simpleperf_runtest_two_functions_arm64': [
{
@@ -1083,7 +1111,7 @@ class TestTools(unittest.TestCase):
{
'func_addr': 0x840,
'addr': 0x840,
- 'source': 'system/extras/simpleperf/runtest/two_functions.cpp:6',
+ 'source': 'system/extras/simpleperf/runtest/two_functions.cpp:7',
'function': 'Function1()',
},
{
@@ -1145,7 +1173,7 @@ class TestTools(unittest.TestCase):
self.assertEqual(source[2], expected_functions[i])
def test_objdump(self):
- binary_cache_path = 'testdata'
+ binary_cache_path = TEST_HELPER.testdata_dir
test_map = {
'/simpleperf_runtest_two_functions_arm64': {
'start_addr': 0x668,
@@ -1196,7 +1224,7 @@ class TestTools(unittest.TestCase):
def test_readelf(self):
test_map = {
- '/simpleperf_runtest_two_functions_arm64': {
+ 'simpleperf_runtest_two_functions_arm64': {
'arch': 'arm64',
'build_id': '0xe8ecb3916d989dbdc068345c30f0c24300000000',
'sections': ['.interp', '.note.android.ident', '.note.gnu.build-id', '.dynsym',
@@ -1208,21 +1236,21 @@ class TestTools(unittest.TestCase):
'.debug_pubnames', '.debug_pubtypes', '.debug_line',
'.note.gnu.gold-version', '.symtab', '.strtab', '.shstrtab'],
},
- '/simpleperf_runtest_two_functions_arm': {
+ 'simpleperf_runtest_two_functions_arm': {
'arch': 'arm',
'build_id': '0x718f5b36c4148ee1bd3f51af89ed2be600000000',
},
- '/simpleperf_runtest_two_functions_x86_64': {
+ 'simpleperf_runtest_two_functions_x86_64': {
'arch': 'x86_64',
},
- '/simpleperf_runtest_two_functions_x86': {
+ 'simpleperf_runtest_two_functions_x86': {
'arch': 'x86',
}
}
readelf = ReadElf(None)
for dso_path in test_map:
dso_info = test_map[dso_path]
- path = 'testdata' + dso_path
+ path = os.path.join(TEST_HELPER.testdata_dir, dso_path)
self.assertEqual(dso_info['arch'], readelf.get_arch(path))
if 'build_id' in dso_info:
self.assertEqual(dso_info['build_id'], readelf.get_build_id(path))
@@ -1233,31 +1261,33 @@ class TestTools(unittest.TestCase):
self.assertEqual(readelf.get_sections('not_exist_file'), [])
def test_source_file_searcher(self):
- searcher = SourceFileSearcher(['testdata'])
+ searcher = SourceFileSearcher(
+ [TEST_HELPER.testdata_path('SimpleperfExampleWithNative'),
+ TEST_HELPER.testdata_path('SimpleperfExampleOfKotlin')])
def format_path(path):
- return path.replace('/', os.sep)
+ return os.path.join(TEST_HELPER.testdata_dir, path.replace('/', os.sep))
# Find a C++ file with pure file name.
self.assertEqual(
- format_path('testdata/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
+ format_path('SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
searcher.get_real_path('native-lib.cpp'))
# Find a C++ file with an absolute file path.
self.assertEqual(
- format_path('testdata/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
+ format_path('SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
searcher.get_real_path('/data/native-lib.cpp'))
# Find a Java file.
self.assertEqual(
- format_path('testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/' +
+ format_path('SimpleperfExampleWithNative/app/src/main/java/com/example/' +
'simpleperf/simpleperfexamplewithnative/MainActivity.java'),
searcher.get_real_path('simpleperfexamplewithnative/MainActivity.java'))
# Find a Kotlin file.
self.assertEqual(
- format_path('testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/' +
+ format_path('SimpleperfExampleOfKotlin/app/src/main/java/com/example/' +
'simpleperf/simpleperfexampleofkotlin/MainActivity.kt'),
searcher.get_real_path('MainActivity.kt'))
def test_is_elf_file(self):
- self.assertTrue(is_elf_file(os.path.join(
- 'testdata', 'simpleperf_runtest_two_functions_arm')))
+ self.assertTrue(is_elf_file(TEST_HELPER.testdata_path(
+ 'simpleperf_runtest_two_functions_arm')))
with open('not_elf', 'wb') as fh:
fh.write(b'\x90123')
try:
@@ -1266,13 +1296,15 @@ class TestTools(unittest.TestCase):
remove('not_elf')
-class TestNativeLibDownloader(unittest.TestCase):
+class TestNativeLibDownloader(TestBase):
def setUp(self):
- self.adb = AdbHelper()
+ super(TestNativeLibDownloader, self).setUp()
+ self.adb = TEST_HELPER.adb
self.adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
def tearDown(self):
self.adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
+ super(TestNativeLibDownloader, self).tearDown()
def test_smoke(self):
def is_lib_on_device(path):
@@ -1280,9 +1312,8 @@ class TestNativeLibDownloader(unittest.TestCase):
# Sync all native libs on device.
downloader = NativeLibDownloader(None, 'arm64', self.adb)
- downloader.collect_native_libs_on_host(os.path.join(
- 'testdata', 'SimpleperfExampleWithNative', 'app', 'build', 'intermediates', 'cmake',
- 'profiling'))
+ downloader.collect_native_libs_on_host(TEST_HELPER.testdata_path(
+ 'SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling'))
self.assertEqual(len(downloader.host_build_id_map), 2)
for entry in downloader.host_build_id_map.values():
self.assertEqual(entry.score, 3)
@@ -1330,15 +1361,15 @@ class TestNativeLibDownloader(unittest.TestCase):
class TestReportHtml(TestBase):
def test_long_callchain(self):
self.run_cmd(['report_html.py', '-i',
- os.path.join('testdata', 'perf_with_long_callchain.data')])
+ TEST_HELPER.testdata_path('perf_with_long_callchain.data')])
def test_aggregated_by_thread_name(self):
# Calculate event_count for each thread name before aggregation.
event_count_for_thread_name = collections.defaultdict(lambda: 0)
# use "--min_func_percent 0" to avoid cutting any thread.
self.run_cmd(['report_html.py', '--min_func_percent', '0', '-i',
- os.path.join('testdata', 'aggregatable_perf1.data'),
- os.path.join('testdata', 'aggregatable_perf2.data')])
+ TEST_HELPER.testdata_path('aggregatable_perf1.data'),
+ TEST_HELPER.testdata_path('aggregatable_perf2.data')])
record_data = self._load_record_data_in_html('report.html')
event = record_data['sampleInfo'][0]
for process in event['processes']:
@@ -1349,8 +1380,8 @@ class TestReportHtml(TestBase):
# Check event count for each thread after aggregation.
self.run_cmd(['report_html.py', '--aggregate-by-thread-name',
'--min_func_percent', '0', '-i',
- os.path.join('testdata', 'aggregatable_perf1.data'),
- os.path.join('testdata', 'aggregatable_perf2.data')])
+ TEST_HELPER.testdata_path('aggregatable_perf1.data'),
+ TEST_HELPER.testdata_path('aggregatable_perf2.data')])
record_data = self._load_record_data_in_html('report.html')
event = record_data['sampleInfo'][0]
hit_count = 0
@@ -1364,7 +1395,7 @@ class TestReportHtml(TestBase):
def test_no_empty_process(self):
""" Test not showing a process having no threads. """
- perf_data = os.path.join('testdata', 'two_process_perf.data')
+ perf_data = TEST_HELPER.testdata_path('two_process_perf.data')
self.run_cmd(['report_html.py', '-i', perf_data])
record_data = self._load_record_data_in_html('report.html')
processes = record_data['sampleInfo'][0]['processes']
@@ -1398,11 +1429,11 @@ class TestBinaryCacheBuilder(TestBase):
readelf = ReadElf(None)
strip = find_tool_path('strip', arch='arm')
self.assertIsNotNone(strip)
- symfs_dir = os.path.join('testdata', 'symfs_dir')
+ symfs_dir = os.path.join(self.test_dir, 'symfs_dir')
remove(symfs_dir)
os.mkdir(symfs_dir)
filename = 'simpleperf_runtest_two_functions_arm'
- origin_file = os.path.join('testdata', filename)
+ origin_file = TEST_HELPER.testdata_path(filename)
source_file = os.path.join(symfs_dir, filename)
target_file = os.path.join('binary_cache', filename)
expected_build_id = readelf.get_build_id(origin_file)
@@ -1428,14 +1459,14 @@ class TestBinaryCacheBuilder(TestBase):
class TestApiProfiler(TestBase):
def run_api_test(self, package_name, apk_name, expected_reports, min_android_version):
- adb = AdbHelper()
- if android_version() < ord(min_android_version) - ord('L') + 5:
+ adb = TEST_HELPER.adb
+ if TEST_HELPER.android_version < ord(min_android_version) - ord('L') + 5:
log_info('skip this test on Android < %s.' % min_android_version)
return
# step 1: Prepare profiling.
self.run_cmd(['api_profiler.py', 'prepare'])
# step 2: Install and run the app.
- apk_path = os.path.join('testdata', apk_name)
+ apk_path = TEST_HELPER.testdata_path(apk_name)
adb.run(['uninstall', package_name])
adb.check_run(['install', '-t', apk_path])
adb.check_run(['shell', 'am', 'start', '-n', package_name + '/.MainActivity'])
@@ -1458,8 +1489,6 @@ class TestApiProfiler(TestBase):
self.run_cmd(['report.py', '-g', '-o', 'report.txt', '-i', path])
self.check_strings_in_file('report.txt', expected_reports)
# step 6: Clean up.
- remove('report.txt')
- remove('simpleperf_data')
adb.check_run(['uninstall', package_name])
def run_cpp_api_test(self, apk_name, min_android_version):
@@ -1504,12 +1533,13 @@ class TestApiProfiler(TestBase):
class TestPprofProtoGenerator(TestBase):
def setUp(self):
+ super(TestPprofProtoGenerator, self).setUp()
if not HAS_GOOGLE_PROTOBUF:
raise unittest.SkipTest(
'Skip test for pprof_proto_generator because google.protobuf is missing')
def run_generator(self, options=None, testdata_file='perf_with_interpreter_frames.data'):
- testdata_path = os.path.join('testdata', testdata_file)
+ testdata_path = TEST_HELPER.testdata_path(testdata_file)
options = options or []
self.run_cmd(['pprof_proto_generator.py', '-i', testdata_path] + options)
return self.run_cmd(['pprof_proto_generator.py', '--show'], return_output=True)
@@ -1565,7 +1595,7 @@ class TestPprofProtoGenerator(TestBase):
mapping.
"""
self.run_cmd(['pprof_proto_generator.py', '-i',
- os.path.join('testdata', 'perf_with_interpreter_frames.data')])
+ TEST_HELPER.testdata_path('perf_with_interpreter_frames.data')])
profile = load_pprof_profile('pprof.profile')
# pylint: disable=no-member
@@ -1577,12 +1607,14 @@ class TestPprofProtoGenerator(TestBase):
class TestRecordingRealApps(TestBase):
def setUp(self):
- self.adb = AdbHelper(False)
+ super(TestRecordingRealApps, self).setUp()
+ self.adb = TEST_HELPER.adb
self.installed_packages = []
def tearDown(self):
for package in self.installed_packages:
self.adb.run(['shell', 'pm', 'uninstall', package])
+ super(TestRecordingRealApps, self).tearDown()
def install_apk(self, apk_path, package_name):
self.adb.run(['install', '-t', apk_path])
@@ -1600,20 +1632,21 @@ class TestRecordingRealApps(TestBase):
self.check_strings_in_file('report.txt', [symbol_name])
def test_recording_displaybitmaps(self):
- self.install_apk(os.path.join('testdata', 'DisplayBitmaps.apk'),
+ self.install_apk(TEST_HELPER.testdata_path('DisplayBitmaps.apk'),
'com.example.android.displayingbitmaps')
- self.install_apk(os.path.join('testdata', 'DisplayBitmapsTest.apk'),
+ self.install_apk(TEST_HELPER.testdata_path('DisplayBitmapsTest.apk'),
'com.example.android.displayingbitmaps.test')
self.start_app('shell am instrument -w -r -e debug false -e class ' +
'com.example.android.displayingbitmaps.tests.GridViewTest ' +
'com.example.android.displayingbitmaps.test/' +
'androidx.test.runner.AndroidJUnitRunner')
self.record_data('com.example.android.displayingbitmaps', '-e cpu-clock -g --duration 10')
- if android_version() >= 9:
+ if TEST_HELPER.android_version >= 9:
self.check_symbol_in_record_file('androidx.test.espresso')
def test_recording_endless_tunnel(self):
- self.install_apk(os.path.join('testdata', 'EndlessTunnel.apk'), 'com.google.sample.tunnel')
+ self.install_apk(TEST_HELPER.testdata_path(
+ 'EndlessTunnel.apk'), 'com.google.sample.tunnel')
self.start_app('shell am start -n com.google.sample.tunnel/android.app.NativeActivity -a ' +
'android.intent.action.MAIN -c android.intent.category.LAUNCHER')
self.record_data('com.google.sample.tunnel', '-e cpu-clock -g --duration 10')
@@ -1631,18 +1664,19 @@ def get_all_tests():
return sorted(tests)
-def run_tests(tests, repeats, python_version):
- os.chdir(get_script_dir())
- build_testdata()
+def run_tests(tests, repeats):
+ TEST_HELPER.build_testdata()
argv = [sys.argv[0]] + tests
test_runner = unittest.TextTestRunner(stream=TEST_LOGGER, verbosity=2)
- for repeat in range(repeats):
+ success = True
+ for repeat in range(1, repeats + 1):
print('Run tests with python %d for %dth time\n%s' % (
- python_version, repeat + 1, '\n'.join(tests)), file=TEST_LOGGER)
+ TEST_HELPER.python_version, repeat, '\n'.join(tests)), file=TEST_LOGGER)
+ TEST_HELPER.repeat_count = repeat
test_program = unittest.main(argv=argv, testRunner=test_runner, exit=False)
if not test_program.result.wasSuccessful():
- return False
- return True
+ success = False
+ return success
def main():
@@ -1654,6 +1688,7 @@ def main():
parser.add_argument('--repeat', type=int, nargs=1, default=[1], help='run test multiple times')
parser.add_argument('--no-test-result', dest='report_test_result',
action='store_false', help="Don't report test result.")
+ parser.add_argument('--browser', action='store_true', help='pop report html file in browser.')
parser.add_argument('pattern', nargs='*', help='Run tests matching the selected pattern.')
args = parser.parse_args()
tests = get_all_tests()
@@ -1668,16 +1703,12 @@ def main():
log_exit("Can't find test %s" % args.test_from[0])
tests = tests[start_pos:]
if args.pattern:
- pattern = re.compile(fnmatch.translate(args.pattern[0]))
- new_tests = []
- for test in tests:
- if pattern.match(test):
- new_tests.append(test)
- tests = new_tests
+ patterns = [re.compile(fnmatch.translate(x)) for x in args.pattern]
+ tests = [t for t in tests if any(pattern.match(t) for pattern in patterns)]
if not tests:
log_exit('No tests are matched.')
- if android_version() < 7:
+ if TEST_HELPER.android_version < 7:
print("Skip tests on Android version < N.", file=TEST_LOGGER)
return False
@@ -1685,14 +1716,21 @@ def main():
python_versions = [2, 3]
else:
python_versions = [int(args.python_version)]
+
+ for python_version in python_versions:
+ remove(TEST_HELPER.get_test_base_dir(python_version))
+
+ if not args.browser:
+ TEST_HELPER.browser_option = ['--no_browser']
+
test_results = []
- current_version = 3 if is_python3() else 2
for version in python_versions:
- if version == current_version:
- test_result = run_tests(tests, args.repeat[0], version)
+ os.chdir(TEST_HELPER.cur_dir)
+ if version == TEST_HELPER.python_version:
+ test_result = run_tests(tests, args.repeat[0])
else:
argv = ['python3' if version == 3 else 'python']
- argv.append(os.path.join(get_script_dir(), 'test.py'))
+ argv.append(TEST_HELPER.script_path('test.py'))
argv += sys.argv[1:]
argv += ['--python-version', str(version), '--no-test-result']
test_result = subprocess.call(argv) == 0
diff --git a/simpleperf/scripts/utils.py b/simpleperf/scripts/utils.py
index e0d40b24..5754f383 100644
--- a/simpleperf/scripts/utils.py
+++ b/simpleperf/scripts/utils.py
@@ -326,6 +326,7 @@ class AdbHelper(object):
def get_android_version(self):
+ """ Get Android version on device, like 7 is for Android N, 8 is for Android O."""
build_version = self.get_property('ro.build.version.release')
android_version = 0
if build_version: