OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/installer/setup/installer_metrics.h" | |
6 | |
7 #include <windows.h> // NOLINT | |
8 #include <atlsecurity.h> | |
9 | |
10 #include "base/files/file_enumerator.h" | |
11 #include "base/files/file_path.h" | |
12 #include "base/files/file_util.h" | |
13 #include "base/files/important_file_writer.h" | |
14 #include "base/metrics/histogram_base.h" | |
15 #include "base/metrics/persistent_histogram_allocator.h" | |
16 #include "base/metrics/persistent_memory_allocator.h" | |
17 #include "base/strings/string_piece.h" | |
18 #include "base/strings/stringprintf.h" | |
19 #include "base/time/time.h" | |
20 #include "chrome/installer/util/util_constants.h" | |
21 | |
22 namespace installer { | |
23 | |
24 namespace { | |
25 | |
26 // This is duplicated from components/metrics/file_metrics_provider.h which is | |
27 // not accessible from setup code. | |
28 const base::FilePath::CharType MetricsFileExtension[] = | |
29 FILE_PATH_LITERAL(".pma"); | |
30 | |
31 // Add to the ACL of an object on disk. This follows the method from MSDN: | |
32 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa379283.aspx | |
33 // This is done using explicit flags rather than the "security string" format | |
34 // because strings do not necessarily read what is written which makes it | |
35 // difficult to de-dup. Working with the binary format is always exact and | |
36 // the system libraries will properly ignore duplicate ACL entries. | |
37 bool AddAclToPath(const base::FilePath& path, | |
38 const CSid& trustee, | |
39 ACCESS_MASK access_mask, | |
40 BYTE ace_flags) { | |
41 DCHECK(!path.empty()); | |
42 DCHECK(trustee); | |
43 | |
44 // Get the existing DACL. | |
45 ATL::CDacl dacl; | |
46 if (!ATL::AtlGetDacl(path.value().c_str(), SE_FILE_OBJECT, &dacl)) { | |
47 DPLOG(ERROR) << "Failed getting DACL for path \"" << path.value() << "\""; | |
48 return false; | |
49 } | |
50 | |
51 // Check if the requested access already exists and return if so. | |
52 for (UINT i = 0; i < dacl.GetAceCount(); ++i) { | |
53 ATL::CSid sid; | |
54 ACCESS_MASK mask = 0; | |
55 BYTE type = 0; | |
56 BYTE flags = 0; | |
57 dacl.GetAclEntry(i, &sid, &mask, &type, &flags); | |
58 if (sid == trustee && type == ACCESS_ALLOWED_ACE_TYPE && | |
59 (flags & ace_flags) == ace_flags && | |
60 (mask & access_mask) == access_mask) { | |
61 return true; | |
62 } | |
63 } | |
64 | |
65 // Add the new access to the DACL. | |
66 if (!dacl.AddAllowedAce(trustee, access_mask, ace_flags)) { | |
67 DPLOG(ERROR) << "Failed adding ACE to DACL"; | |
68 return false; | |
69 } | |
70 | |
71 // Attach the updated ACL as the object's DACL. | |
72 if (!ATL::AtlSetDacl(path.value().c_str(), SE_FILE_OBJECT, dacl)) { | |
73 DPLOG(ERROR) << "Failed setting DACL for path \"" << path.value() << "\""; | |
74 return false; | |
75 } | |
76 | |
77 return true; | |
78 } | |
79 | |
80 } // namespace | |
81 | |
82 base::FilePath GetPersistentHistogramStorageDir( | |
83 const base::FilePath& target_path) { | |
84 return target_path.AppendASCII(kSetupHistogramAllocatorName); | |
85 } | |
86 | |
87 void BeginPersistentHistogramStorage() { | |
88 base::GlobalHistogramAllocator::CreateWithLocalMemory( | |
89 1 << 20, // 1 MiB | |
90 0, // No identifier. | |
91 installer::kSetupHistogramAllocatorName); | |
92 base::GlobalHistogramAllocator::Get()->CreateTrackingHistograms( | |
93 kSetupHistogramAllocatorName); | |
94 | |
95 // This can't be enabled until after the allocator is configured because | |
96 // there is no other reporting out of setup other than persistent memory. | |
97 base::HistogramBase::EnableActivityReportHistogram("setup"); | |
98 } | |
99 | |
100 void EndPersistentHistogramStorage(const base::FilePath& target_path, | |
101 bool system_install) { | |
102 base::PersistentHistogramAllocator* allocator = | |
103 base::GlobalHistogramAllocator::Get(); | |
104 allocator->UpdateTrackingHistograms(); | |
105 | |
106 // Allocator dumps are saved to a directory that was created earlier. Stop | |
107 // now if that directory has been removed because an uninstall has happened. | |
108 base::FilePath dir_path = GetPersistentHistogramStorageDir(target_path); | |
109 if (!base::DirectoryExists(dir_path)) | |
110 return; | |
111 | |
112 // Set permissions on the directory that allows other processes, including | |
113 // non-privileged ones, to read and delete the files stored there. This | |
114 // allows the browser process to remove the metrics files once it's done | |
115 // reading them. This is only done for system-level installs; user-level | |
116 // installs already provide delete-file access to the browser process. | |
117 if (system_install) { | |
118 if (!AddAclToPath(dir_path, ATL::Sids::AuthenticatedUser(), | |
119 FILE_GENERIC_READ | FILE_DELETE_CHILD, | |
120 CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)) { | |
121 PLOG(ERROR) << "Could not set \"delete\" permission for metrics directory" | |
122 << " \"" << dir_path.value() << "\""; | |
123 } | |
124 } | |
125 | |
126 // Remove any existing metrics file at the old (non-subdir) pathname. | |
127 base::DeleteFile(dir_path.AddExtension(MetricsFileExtension), false); | |
128 | |
129 // Save data using the current time as the filename. The actual filename | |
130 // doesn't matter (so long as it ends with the correct extension) but this | |
131 // works as well as anything. | |
132 base::Time::Exploded exploded; | |
133 base::Time::Now().LocalExplode(&exploded); | |
134 base::FilePath file_path = | |
135 dir_path | |
136 .AppendASCII(base::StringPrintf("%04d%02d%02d%02d%02d%02d", | |
137 exploded.year, exploded.month, | |
138 exploded.day_of_month, exploded.hour, | |
139 exploded.minute, exploded.second)) | |
140 .AddExtension(MetricsFileExtension); | |
141 | |
142 base::StringPiece contents(static_cast<const char*>(allocator->data()), | |
143 allocator->used()); | |
144 if (base::ImportantFileWriter::WriteFileAtomically(file_path, contents)) | |
145 VLOG(1) << "Persistent histograms saved in file: " << file_path.value(); | |
146 } | |
147 | |
148 } // namespace installer | |
OLD | NEW |