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