dropbox.cc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. *
  3. * Copyright 2017, 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. */
  17. #include "dropbox.h"
  18. #include <cstdio>
  19. #include <cstdlib>
  20. #include <memory>
  21. #include <inttypes.h>
  22. #include <unistd.h>
  23. #include <android-base/logging.h>
  24. #include <android-base/stringprintf.h>
  25. #include <android-base/unique_fd.h>
  26. #include <android/os/DropBoxManager.h>
  27. #include <binder/Status.h>
  28. #include <utils/String8.h>
  29. #include "perfprofd_record.pb.h"
  30. #include "perfprofd_io.h"
  31. namespace android {
  32. namespace perfprofd {
  33. namespace dropbox {
  34. namespace {
  35. bool WriteDropboxFile(android::perfprofd::PerfprofdRecord* encodedProfile,
  36. const std::string& temp_dir,
  37. std::string* error_msg) {
  38. android::base::unique_fd tmp_fd;
  39. {
  40. char path[PATH_MAX];
  41. snprintf(path, sizeof(path), "%s/dropboxtmp-XXXXXX", temp_dir.c_str());
  42. tmp_fd.reset(mkstemp(path));
  43. if (tmp_fd.get() == -1) {
  44. *error_msg = android::base::StringPrintf("Could not create temp file %s: %s",
  45. path,
  46. strerror(errno));
  47. return false;
  48. }
  49. if (unlink(path) != 0) {
  50. PLOG(WARNING) << "Could not unlink binder temp file";
  51. }
  52. }
  53. // Dropbox takes ownership of the fd, and if it is not readonly,
  54. // a selinux violation will occur. Get a read-only version.
  55. android::base::unique_fd read_only;
  56. {
  57. char fdpath[64];
  58. snprintf(fdpath, arraysize(fdpath), "/proc/self/fd/%d", tmp_fd.get());
  59. read_only.reset(open(fdpath, O_RDONLY | O_CLOEXEC));
  60. if (read_only.get() < 0) {
  61. *error_msg = android::base::StringPrintf("Could not create read-only fd: %s",
  62. strerror(errno));
  63. return false;
  64. }
  65. }
  66. constexpr bool kCompress = true; // Ignore the config here. Dropbox will always end up
  67. // compressing the data, might as well make the temp
  68. // file smaller and help it out.
  69. using DropBoxManager = android::os::DropBoxManager;
  70. constexpr int kDropboxFlags = DropBoxManager::IS_GZIPPED;
  71. if (!SerializeProtobuf(encodedProfile, std::move(tmp_fd), kCompress)) {
  72. *error_msg = "Could not serialize to temp file";
  73. return false;
  74. }
  75. sp<DropBoxManager> dropbox(new DropBoxManager());
  76. android::binder::Status status = dropbox->addFile(String16("perfprofd"),
  77. read_only.release(),
  78. kDropboxFlags);
  79. if (!status.isOk()) {
  80. *error_msg = status.toString8();
  81. return false;
  82. }
  83. return true;
  84. }
  85. } // namespace
  86. bool SendToDropbox(android::perfprofd::PerfprofdRecord* profile,
  87. const std::string& temp_directory,
  88. std::string* error_msg) {
  89. size_t size = profile->ByteSize();
  90. if (size < 1024 * 1024) {
  91. // For a small size, send as a byte buffer directly.
  92. std::unique_ptr<uint8_t[]> data(new uint8_t[size]);
  93. profile->SerializeWithCachedSizesToArray(data.get());
  94. using DropBoxManager = android::os::DropBoxManager;
  95. sp<DropBoxManager> dropbox(new DropBoxManager());
  96. android::binder::Status status = dropbox->addData(String16("perfprofd"),
  97. data.get(),
  98. size,
  99. 0);
  100. if (!status.isOk()) {
  101. *error_msg = status.toString8();
  102. return false;
  103. }
  104. return true;
  105. } else {
  106. // For larger buffers, we need to go through the filesystem.
  107. return WriteDropboxFile(profile, temp_directory, error_msg);
  108. }
  109. }
  110. } // namespace dropbox
  111. } // namespace perfprofd
  112. } // namespace android