1 /*
2  * Copyright (C) 2012 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  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CRASH_REPORTER_CRASH_COLLECTOR_H_
18 #define CRASH_REPORTER_CRASH_COLLECTOR_H_
19 
20 #include <sys/stat.h>
21 
22 #include <map>
23 #include <string>
24 
25 #include <base/files/file_path.h>
26 #include <base/macros.h>
27 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
28 
29 // User crash collector.
30 class CrashCollector {
31  public:
32   typedef void (*CountCrashFunction)();
33   typedef bool (*IsFeedbackAllowedFunction)();
34 
35   CrashCollector();
36 
37   virtual ~CrashCollector();
38 
39   // Initialize the crash collector for detection of crashes, given a
40   // crash counting function, and metrics collection enabled oracle.
41   void Initialize(CountCrashFunction count_crash,
42                   IsFeedbackAllowedFunction is_metrics_allowed);
43 
44  protected:
45   friend class CrashCollectorTest;
46   FRIEND_TEST(ChromeCollectorTest, HandleCrash);
47   FRIEND_TEST(CrashCollectorTest, CheckHasCapacityCorrectBasename);
48   FRIEND_TEST(CrashCollectorTest, CheckHasCapacityStrangeNames);
49   FRIEND_TEST(CrashCollectorTest, CheckHasCapacityUsual);
50   FRIEND_TEST(CrashCollectorTest, GetCrashDirectoryInfo);
51   FRIEND_TEST(CrashCollectorTest, GetCrashPath);
52   FRIEND_TEST(CrashCollectorTest, GetLogContents);
53   FRIEND_TEST(CrashCollectorTest, ForkExecAndPipe);
54   FRIEND_TEST(CrashCollectorTest, FormatDumpBasename);
55   FRIEND_TEST(CrashCollectorTest, Initialize);
56   FRIEND_TEST(CrashCollectorTest, MetaData);
57   FRIEND_TEST(CrashCollectorTest, Sanitize);
58   FRIEND_TEST(CrashCollectorTest, WriteNewFile);
59   FRIEND_TEST(ForkExecAndPipeTest, Basic);
60   FRIEND_TEST(ForkExecAndPipeTest, NonZeroReturnValue);
61   FRIEND_TEST(ForkExecAndPipeTest, BadOutputFile);
62   FRIEND_TEST(ForkExecAndPipeTest, ExistingOutputFile);
63   FRIEND_TEST(ForkExecAndPipeTest, BadExecutable);
64   FRIEND_TEST(ForkExecAndPipeTest, StderrCaptured);
65   FRIEND_TEST(ForkExecAndPipeTest, NULLParam);
66   FRIEND_TEST(ForkExecAndPipeTest, NoParams);
67   FRIEND_TEST(ForkExecAndPipeTest, SegFaultHandling);
68 
69   // Set maximum enqueued crashes in a crash directory.
70   static const int kMaxCrashDirectorySize;
71 
72   // Writes |data| of |size| to |filename|, which must be a new file.
73   // If the file already exists or writing fails, return a negative value.
74   // Otherwise returns the number of bytes written.
75   int WriteNewFile(const base::FilePath &filename, const char *data, int size);
76 
77   // Return a filename that has only [a-z0-1_] characters by mapping
78   // all others into '_'.
79   std::string Sanitize(const std::string &name);
80 
81   // For testing, set the directory always returned by
82   // GetCreatedCrashDirectoryByEuid.
ForceCrashDirectory(const base::FilePath & forced_directory)83   void ForceCrashDirectory(const base::FilePath &forced_directory) {
84     forced_crash_directory_ = forced_directory;
85   }
86 
87   base::FilePath GetCrashDirectoryInfo(mode_t *mode,
88                                        uid_t *directory_owner,
89                                        gid_t *directory_group);
90   bool GetUserInfoFromName(const std::string &name,
91                            uid_t *uid,
92                            gid_t *gid);
93 
94   // Determines the crash directory for given euid, and creates the
95   // directory if necessary with appropriate permissions.  If
96   // |out_of_capacity| is not nullptr, it is set to indicate if the call
97   // failed due to not having capacity in the crash directory. Returns
98   // true whether or not directory needed to be created, false on any
99   // failure.  If the crash directory is at capacity, returns false.
100   bool GetCreatedCrashDirectoryByEuid(uid_t euid,
101                                       base::FilePath *crash_file_path,
102                                       bool *out_of_capacity);
103 
104   // Format crash name based on components.
105   std::string FormatDumpBasename(const std::string &exec_name,
106                                  time_t timestamp,
107                                  pid_t pid);
108 
109   // Create a file path to a file in |crash_directory| with the given
110   // |basename| and |extension|.
111   base::FilePath GetCrashPath(const base::FilePath &crash_directory,
112                               const std::string &basename,
113                               const std::string &extension);
114 
115   base::FilePath GetProcessPath(pid_t pid);
116   bool GetSymlinkTarget(const base::FilePath &symlink,
117                         base::FilePath *target);
118   bool GetExecutableBaseNameFromPid(pid_t pid,
119                                     std::string *base_name);
120 
121   // Check given crash directory still has remaining capacity for another
122   // crash.
123   bool CheckHasCapacity(const base::FilePath &crash_directory);
124 
125   // Write a log applicable to |exec_name| to |output_file| based on the
126   // log configuration file at |config_path|.
127   bool GetLogContents(const base::FilePath &config_path,
128                       const std::string &exec_name,
129                       const base::FilePath &output_file);
130 
131   // Add non-standard meta data to the crash metadata file.  Call
132   // before calling WriteCrashMetaData.  Key must not contain "=" or
133   // "\n" characters.  Value must not contain "\n" characters.
134   void AddCrashMetaData(const std::string &key, const std::string &value);
135 
136   // Add a file to be uploaded to the crash reporter server. The file must
137   // persist until the crash report is sent; ideally it should live in the same
138   // place as the .meta file, so it can be cleaned up automatically.
139   void AddCrashMetaUploadFile(const std::string &key, const std::string &path);
140 
141   // Add non-standard meta data to the crash metadata file.
142   // Data added though this call will be uploaded to the crash reporter server,
143   // appearing as a form field.
144   void AddCrashMetaUploadData(const std::string &key, const std::string &value);
145 
146   // Write a file of metadata about crash.
147   void WriteCrashMetaData(const base::FilePath &meta_path,
148                           const std::string &exec_name,
149                           const std::string &payload_path);
150 
151   // Returns true if the a crash test is currently running.
152   bool IsCrashTestInProgress();
153   // Returns true if we should consider ourselves to be running on a
154   // developer image.
155   bool IsDeveloperImage();
156 
157   CountCrashFunction count_crash_function_;
158   IsFeedbackAllowedFunction is_feedback_allowed_function_;
159   std::string extra_metadata_;
160   base::FilePath forced_crash_directory_;
161   base::FilePath log_config_path_;
162 
163  private:
164   DISALLOW_COPY_AND_ASSIGN(CrashCollector);
165 };
166 
167 #endif  // CRASH_REPORTER_CRASH_COLLECTOR_H_
168