SharedPrefMap.cpp (7519B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "SharedPrefMap.h" 8 9 #include "mozilla/dom/ipc/MemMapSnapshot.h" 10 11 #include "mozilla/BinarySearch.h" 12 #include "mozilla/ResultExtensions.h" 13 #include "mozilla/Try.h" 14 #include "mozilla/ipc/FileDescriptor.h" 15 16 namespace mozilla { 17 18 using namespace ipc; 19 20 static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) { 21 auto mod = aOffset % aAlign; 22 return mod ? aAlign - mod : 0; 23 } 24 25 SharedPrefMap::SharedPrefMap(const ReadOnlySharedMemoryHandle& aMapHandle) { 26 auto map = aMapHandle.Map(); 27 MOZ_RELEASE_ASSERT(map); 28 29 mHandle = aMapHandle.Clone(); 30 // We return literal nsCStrings pointing to the mapped data for preference 31 // names and string values, which means that we may still have references to 32 // the mapped data even after this instance is destroyed. That means that we 33 // need to keep the mapping alive until process shutdown, in order to be safe. 34 mMappedMemory = std::move(map).Release(); 35 } 36 37 SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) { 38 ReadOnlySharedMemoryMappingWithHandle mapWithHandle; 39 auto result = aBuilder.Finalize(); 40 MOZ_RELEASE_ASSERT(result.isOk()); 41 mHandle = result.unwrap(); 42 auto map = mHandle.Map(); 43 MOZ_RELEASE_ASSERT(map.IsValid()); 44 mMappedMemory = std::move(map).Release(); 45 } 46 47 mozilla::ipc::ReadOnlySharedMemoryHandle SharedPrefMap::CloneHandle() const { 48 MOZ_ASSERT(XRE_IsParentProcess()); 49 return mHandle.Clone(); 50 } 51 52 bool SharedPrefMap::Has(const char* aKey) const { 53 size_t index; 54 return Find(aKey, &index); 55 } 56 57 Maybe<const SharedPrefMap::Pref> SharedPrefMap::Get(const char* aKey) const { 58 Maybe<const Pref> result; 59 60 size_t index; 61 if (Find(aKey, &index)) { 62 result.emplace(Pref{this, &Entries()[index]}); 63 } 64 65 return result; 66 } 67 68 bool SharedPrefMap::Find(const char* aKey, size_t* aIndex) const { 69 const auto& keys = KeyTable(); 70 71 return BinarySearchIf( 72 Entries(), 0, EntryCount(), 73 [&](const Entry& aEntry) { 74 return strcmp(aKey, keys.GetBare(aEntry.mKey)); 75 }, 76 aIndex); 77 } 78 79 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags, 80 bool aDefaultValue, bool aUserValue) { 81 mEntries.AppendElement(Entry{ 82 aKey.get(), 83 mKeyTable.Add(aKey), 84 {aDefaultValue, aUserValue}, 85 uint8_t(PrefType::Bool), 86 aFlags.mHasDefaultValue, 87 aFlags.mHasUserValue, 88 aFlags.mIsSticky, 89 aFlags.mIsLocked, 90 aFlags.mIsSanitized, 91 aFlags.mIsSkippedByIteration, 92 }); 93 } 94 95 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags, 96 int32_t aDefaultValue, int32_t aUserValue) { 97 ValueIdx index; 98 if (aFlags.mHasUserValue) { 99 index = mIntValueTable.Add(aDefaultValue, aUserValue); 100 } else { 101 index = mIntValueTable.Add(aDefaultValue); 102 } 103 104 mEntries.AppendElement(Entry{ 105 aKey.get(), 106 mKeyTable.Add(aKey), 107 {index}, 108 uint8_t(PrefType::Int), 109 aFlags.mHasDefaultValue, 110 aFlags.mHasUserValue, 111 aFlags.mIsSticky, 112 aFlags.mIsLocked, 113 aFlags.mIsSanitized, 114 aFlags.mIsSkippedByIteration, 115 }); 116 } 117 118 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags, 119 const nsCString& aDefaultValue, 120 const nsCString& aUserValue) { 121 ValueIdx index; 122 StringTableEntry defaultVal = mValueStringTable.Add(aDefaultValue); 123 if (aFlags.mHasUserValue) { 124 StringTableEntry userVal = mValueStringTable.Add(aUserValue); 125 index = mStringValueTable.Add(defaultVal, userVal); 126 } else { 127 index = mStringValueTable.Add(defaultVal); 128 } 129 130 mEntries.AppendElement(Entry{ 131 aKey.get(), 132 mKeyTable.Add(aKey), 133 {index}, 134 uint8_t(PrefType::String), 135 aFlags.mHasDefaultValue, 136 aFlags.mHasUserValue, 137 aFlags.mIsSticky, 138 aFlags.mIsLocked, 139 aFlags.mIsSanitized, 140 aFlags.mIsSkippedByIteration, 141 }); 142 } 143 144 Result<ReadOnlySharedMemoryHandle, nsresult> SharedPrefMapBuilder::Finalize() { 145 using Header = SharedPrefMap::Header; 146 147 // Create an array of entry pointers for the entry array, and sort it by 148 // preference name prior to serialization, so that entries can be looked up 149 // using binary search. 150 nsTArray<Entry*> entries(mEntries.Length()); 151 for (auto& entry : mEntries) { 152 entries.AppendElement(&entry); 153 } 154 entries.Sort([](const Entry* aA, const Entry* aB) { 155 return strcmp(aA->mKeyString, aB->mKeyString); 156 }); 157 158 Header header = {uint32_t(entries.Length())}; 159 160 size_t offset = sizeof(header); 161 offset += GetAlignmentOffset(offset, alignof(Header)); 162 163 offset += entries.Length() * sizeof(SharedPrefMap::Entry); 164 165 header.mKeyStrings.mOffset = offset; 166 header.mKeyStrings.mSize = mKeyTable.Size(); 167 offset += header.mKeyStrings.mSize; 168 169 offset += GetAlignmentOffset(offset, mIntValueTable.Alignment()); 170 header.mUserIntValues.mOffset = offset; 171 header.mUserIntValues.mSize = mIntValueTable.UserSize(); 172 offset += header.mUserIntValues.mSize; 173 174 offset += GetAlignmentOffset(offset, mIntValueTable.Alignment()); 175 header.mDefaultIntValues.mOffset = offset; 176 header.mDefaultIntValues.mSize = mIntValueTable.DefaultSize(); 177 offset += header.mDefaultIntValues.mSize; 178 179 offset += GetAlignmentOffset(offset, mStringValueTable.Alignment()); 180 header.mUserStringValues.mOffset = offset; 181 header.mUserStringValues.mSize = mStringValueTable.UserSize(); 182 offset += header.mUserStringValues.mSize; 183 184 offset += GetAlignmentOffset(offset, mStringValueTable.Alignment()); 185 header.mDefaultStringValues.mOffset = offset; 186 header.mDefaultStringValues.mSize = mStringValueTable.DefaultSize(); 187 offset += header.mDefaultStringValues.mSize; 188 189 header.mValueStrings.mOffset = offset; 190 header.mValueStrings.mSize = mValueStringTable.Size(); 191 offset += header.mValueStrings.mSize; 192 193 MemMapSnapshot mem; 194 MOZ_TRY(mem.Init(offset)); 195 196 auto headerPtr = mem.Get<Header>(); 197 headerPtr[0] = header; 198 199 auto* entryPtr = reinterpret_cast<SharedPrefMap::Entry*>(&headerPtr[1]); 200 for (auto* entry : entries) { 201 *entryPtr = { 202 entry->mKey, 203 GetValue(*entry), 204 entry->mType, 205 entry->mHasDefaultValue, 206 entry->mHasUserValue, 207 entry->mIsSticky, 208 entry->mIsLocked, 209 entry->mIsSanitized, 210 entry->mIsSkippedByIteration, 211 }; 212 entryPtr++; 213 } 214 215 auto ptr = mem.Get<uint8_t>(); 216 217 mKeyTable.Write({&ptr[header.mKeyStrings.mOffset], header.mKeyStrings.mSize}); 218 219 mValueStringTable.Write( 220 {&ptr[header.mValueStrings.mOffset], header.mValueStrings.mSize}); 221 222 mIntValueTable.WriteDefaultValues( 223 {&ptr[header.mDefaultIntValues.mOffset], header.mDefaultIntValues.mSize}); 224 mIntValueTable.WriteUserValues( 225 {&ptr[header.mUserIntValues.mOffset], header.mUserIntValues.mSize}); 226 227 mStringValueTable.WriteDefaultValues( 228 {&ptr[header.mDefaultStringValues.mOffset], 229 header.mDefaultStringValues.mSize}); 230 mStringValueTable.WriteUserValues( 231 {&ptr[header.mUserStringValues.mOffset], header.mUserStringValues.mSize}); 232 233 mKeyTable.Clear(); 234 mValueStringTable.Clear(); 235 mIntValueTable.Clear(); 236 mStringValueTable.Clear(); 237 mEntries.Clear(); 238 239 return mem.Finalize(); 240 } 241 242 } // namespace mozilla