190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "apps/saved_files_service.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <algorithm>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "apps/saved_files_service_factory.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/basictypes.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/containers/hash_tables.h"
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/value_conversions.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_service.h"
1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_host.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_util.h"
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "extensions/common/permissions/api_permission.h"
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/common/permissions/permission_set.h"
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace apps {
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using extensions::APIPermission;
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using extensions::Extension;
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using extensions::ExtensionHost;
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using extensions::ExtensionPrefs;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Preference keys
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// The file entries that the app has permission to access.
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kFileEntries[] = "file_entries";
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// The path to a file entry that the app had permission to access.
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kFileEntryPath[] = "path";
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Whether or not the the entry refers to a directory.
43424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const char kFileEntryIsDirectory[] = "is_directory";
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// The sequence number in the LRU of the file entry.
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kFileEntrySequenceNumber[] = "sequence_number";
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const size_t kMaxSavedFileEntries = 500;
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kMaxSequenceNumber = kint32max;
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// These might be different to the constant values in tests.
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t g_max_saved_file_entries = kMaxSavedFileEntries;
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int g_max_sequence_number = kMaxSequenceNumber;
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Persists a SavedFileEntry in ExtensionPrefs.
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AddSavedFileEntry(ExtensionPrefs* prefs,
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       const std::string& extension_id,
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       const SavedFileEntry& file_entry) {
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs::ScopedDictionaryUpdate update(
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      prefs, extension_id, kFileEntries);
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* file_entries = update.Get();
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!file_entries)
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    file_entries = update.Create();
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!file_entries->GetDictionaryWithoutPathExpansion(file_entry.id, NULL));
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* file_entry_dict = new base::DictionaryValue();
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  file_entry_dict->Set(kFileEntryPath, CreateFilePathValue(file_entry.path));
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  file_entry_dict->SetBoolean(kFileEntryIsDirectory, file_entry.is_directory);
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  file_entry_dict->SetInteger(kFileEntrySequenceNumber,
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              file_entry.sequence_number);
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  file_entries->SetWithoutPathExpansion(file_entry.id, file_entry_dict);
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Updates the sequence_number of a SavedFileEntry persisted in ExtensionPrefs.
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void UpdateSavedFileEntry(ExtensionPrefs* prefs,
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          const std::string& extension_id,
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          const SavedFileEntry& file_entry) {
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs::ScopedDictionaryUpdate update(
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      prefs, extension_id, kFileEntries);
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* file_entries = update.Get();
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(file_entries);
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* file_entry_dict = NULL;
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  file_entries->GetDictionaryWithoutPathExpansion(file_entry.id,
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                  &file_entry_dict);
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(file_entry_dict);
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  file_entry_dict->SetInteger(kFileEntrySequenceNumber,
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              file_entry.sequence_number);
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Removes a SavedFileEntry from ExtensionPrefs.
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void RemoveSavedFileEntry(ExtensionPrefs* prefs,
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          const std::string& extension_id,
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          const std::string& file_entry_id) {
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs::ScopedDictionaryUpdate update(
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      prefs, extension_id, kFileEntries);
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* file_entries = update.Get();
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!file_entries)
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    file_entries = update.Create();
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  file_entries->RemoveWithoutPathExpansion(file_entry_id, NULL);
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Clears all SavedFileEntry for the app from ExtensionPrefs.
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ClearSavedFileEntries(ExtensionPrefs* prefs,
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const std::string& extension_id) {
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  prefs->UpdateExtensionPref(extension_id, kFileEntries, NULL);
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns all SavedFileEntries for the app.
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::vector<SavedFileEntry> GetSavedFileEntries(
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ExtensionPrefs* prefs,
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& extension_id) {
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<SavedFileEntry> result;
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue* file_entries = NULL;
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!prefs->ReadPrefAsDictionary(extension_id, kFileEntries, &file_entries))
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return result;
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*file_entries); !it.IsAtEnd();
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it.Advance()) {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::DictionaryValue* file_entry = NULL;
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!it.value().GetAsDictionary(&file_entry))
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::Value* path_value;
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!file_entry->Get(kFileEntryPath, &path_value))
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::FilePath file_path;
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!GetValueAsFilePath(*path_value, &file_path))
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
128424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    bool is_directory = false;
129424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    file_entry->GetBoolean(kFileEntryIsDirectory, &is_directory);
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int sequence_number = 0;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!file_entry->GetInteger(kFileEntrySequenceNumber, &sequence_number))
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!sequence_number)
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result.push_back(
136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        SavedFileEntry(it.key(), file_path, is_directory, sequence_number));
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return result;
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
143424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)SavedFileEntry::SavedFileEntry() : is_directory(false), sequence_number(0) {}
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SavedFileEntry::SavedFileEntry(const std::string& id,
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                               const base::FilePath& path,
147424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                               bool is_directory,
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                               int sequence_number)
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : id(id),
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      path(path),
151424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      is_directory(is_directory),
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      sequence_number(sequence_number) {}
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class SavedFilesService::SavedFiles {
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SavedFiles(Profile* profile, const std::string& extension_id);
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ~SavedFiles();
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void RegisterFileEntry(const std::string& id,
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         const base::FilePath& file_path,
161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                         bool is_directory);
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void EnqueueFileEntry(const std::string& id);
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool IsRegistered(const std::string& id) const;
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const SavedFileEntry* GetFileEntry(const std::string& id) const;
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<SavedFileEntry> GetAllFileEntries() const;
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Compacts sequence numbers if the largest sequence number is
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // g_max_sequence_number. Outside of testing, it is set to kint32max, so this
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // will almost never do any real work.
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void MaybeCompactSequenceNumbers();
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void LoadSavedFileEntriesFromPreferences();
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Profile* profile_;
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const std::string extension_id_;
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Contains all file entries that have been registered, keyed by ID. Owns
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // values.
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::hash_map<std::string, SavedFileEntry*> registered_file_entries_;
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  STLValueDeleter<base::hash_map<std::string, SavedFileEntry*> >
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      registered_file_entries_deleter_;
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The queue of file entries that have been retained, keyed by
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // sequence_number. Values are a subset of values in registered_file_entries_.
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This should be kept in sync with file entries stored in extension prefs.
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::map<int, SavedFileEntry*> saved_file_lru_;
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SavedFiles);
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SavedFilesService* SavedFilesService::Get(Profile* profile) {
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return SavedFilesServiceFactory::GetForProfile(profile);
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SavedFilesService::SavedFilesService(Profile* profile)
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : extension_id_to_saved_files_deleter_(&extension_id_to_saved_files_),
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      profile_(profile) {
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  registrar_.Add(this,
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 content::NotificationService::AllSources());
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  registrar_.Add(this,
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 chrome::NOTIFICATION_APP_TERMINATING,
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 content::NotificationService::AllSources());
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SavedFilesService::~SavedFilesService() {}
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::Observe(int type,
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                const content::NotificationSource& source,
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                const content::NotificationDetails& details) {
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (type) {
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      const Extension* extension = host->extension();
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (extension) {
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        ClearQueueIfNoRetainPermission(extension);
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        Clear(extension->id());
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      }
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case chrome::NOTIFICATION_APP_TERMINATING: {
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Stop listening to NOTIFICATION_EXTENSION_HOST_DESTROYED in particular
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // as all extension hosts will be destroyed as a result of shutdown.
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      registrar_.RemoveAll();
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::RegisterFileEntry(const std::string& extension_id,
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                          const std::string& id,
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                          const base::FilePath& file_path,
236424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                          bool is_directory) {
237424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  GetOrInsert(extension_id)->RegisterFileEntry(id, file_path, is_directory);
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::EnqueueFileEntry(const std::string& extension_id,
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         const std::string& id) {
24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GetOrInsert(extension_id)->EnqueueFileEntry(id);
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::vector<SavedFileEntry> SavedFilesService::GetAllFileEntries(
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& extension_id) {
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SavedFiles* saved_files = Get(extension_id);
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (saved_files)
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return saved_files->GetAllFileEntries();
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return GetSavedFileEntries(ExtensionPrefs::Get(profile_), extension_id);
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SavedFilesService::IsRegistered(const std::string& extension_id,
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     const std::string& id) {
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return GetOrInsert(extension_id)->IsRegistered(id);
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const SavedFileEntry* SavedFilesService::GetFileEntry(
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& extension_id,
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& id) {
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return GetOrInsert(extension_id)->GetFileEntry(id);
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::ClearQueueIfNoRetainPermission(
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const Extension* extension) {
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (extensions::util::IsEphemeralApp(extension->id(), profile_) ||
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      !extension->permissions_data()->active_permissions()->HasAPIPermission(
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          APIPermission::kFileSystemRetainEntries)) {
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ClearQueue(extension);
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void SavedFilesService::ClearQueue(const extensions::Extension* extension) {
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ClearSavedFileEntries(ExtensionPrefs::Get(profile_), extension->id());
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Clear(extension->id());
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SavedFilesService::SavedFiles* SavedFilesService::Get(
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& extension_id) const {
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::map<std::string, SavedFiles*>::const_iterator it =
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      extension_id_to_saved_files_.find(extension_id);
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (it != extension_id_to_saved_files_.end())
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return it->second;
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return NULL;
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SavedFilesService::SavedFiles* SavedFilesService::GetOrInsert(
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& extension_id) {
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SavedFiles* saved_files = Get(extension_id);
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (saved_files)
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return saved_files;
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  saved_files = new SavedFiles(profile_, extension_id);
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  extension_id_to_saved_files_.insert(
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::make_pair(extension_id, saved_files));
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return saved_files;
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::Clear(const std::string& extension_id) {
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::map<std::string, SavedFiles*>::iterator it =
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      extension_id_to_saved_files_.find(extension_id);
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (it != extension_id_to_saved_files_.end()) {
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    delete it->second;
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    extension_id_to_saved_files_.erase(it);
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SavedFilesService::SavedFiles::SavedFiles(Profile* profile,
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                          const std::string& extension_id)
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : profile_(profile),
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      extension_id_(extension_id),
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      registered_file_entries_deleter_(&registered_file_entries_) {
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LoadSavedFileEntriesFromPreferences();
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SavedFilesService::SavedFiles::~SavedFiles() {}
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::SavedFiles::RegisterFileEntry(
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& id,
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::FilePath& file_path,
322424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    bool is_directory) {
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (ContainsKey(registered_file_entries_, id))
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  registered_file_entries_.insert(
327424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      std::make_pair(id, new SavedFileEntry(id, file_path, is_directory, 0)));
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::SavedFiles::EnqueueFileEntry(const std::string& id) {
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::hash_map<std::string, SavedFileEntry*>::iterator it =
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      registered_file_entries_.find(id);
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(it != registered_file_entries_.end());
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SavedFileEntry* file_entry = it->second;
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int old_sequence_number = file_entry->sequence_number;
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!saved_file_lru_.empty()) {
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Get the sequence number after the last file entry in the LRU.
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::map<int, SavedFileEntry*>::reverse_iterator it =
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        saved_file_lru_.rbegin();
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (it->second == file_entry)
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    file_entry->sequence_number = it->first + 1;
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // The first sequence number is 1, as 0 means the entry is not in the LRU.
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    file_entry->sequence_number = 1;
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  saved_file_lru_.insert(
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::make_pair(file_entry->sequence_number, file_entry));
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (old_sequence_number) {
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    saved_file_lru_.erase(old_sequence_number);
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UpdateSavedFileEntry(prefs, extension_id_, *file_entry);
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    AddSavedFileEntry(prefs, extension_id_, *file_entry);
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (saved_file_lru_.size() > g_max_saved_file_entries) {
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::map<int, SavedFileEntry*>::iterator it = saved_file_lru_.begin();
35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      it->second->sequence_number = 0;
36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      RemoveSavedFileEntry(prefs, extension_id_, it->second->id);
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      saved_file_lru_.erase(it);
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MaybeCompactSequenceNumbers();
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SavedFilesService::SavedFiles::IsRegistered(const std::string& id) const {
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return ContainsKey(registered_file_entries_, id);
36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const SavedFileEntry* SavedFilesService::SavedFiles::GetFileEntry(
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& id) const {
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::hash_map<std::string, SavedFileEntry*>::const_iterator it =
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      registered_file_entries_.find(id);
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (it == registered_file_entries_.end())
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return NULL;
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return it->second;
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
38090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::vector<SavedFileEntry> SavedFilesService::SavedFiles::GetAllFileEntries()
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const {
38390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<SavedFileEntry> result;
38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (base::hash_map<std::string, SavedFileEntry*>::const_iterator it =
38590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)           registered_file_entries_.begin();
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != registered_file_entries_.end();
38790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       ++it) {
38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result.push_back(*it->second);
38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return result;
39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::SavedFiles::MaybeCompactSequenceNumbers() {
39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(g_max_sequence_number, 0);
39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(static_cast<size_t>(g_max_sequence_number),
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            g_max_saved_file_entries);
39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::map<int, SavedFileEntry*>::reverse_iterator it =
39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      saved_file_lru_.rbegin();
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (it == saved_file_lru_.rend())
40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Only compact sequence numbers if the last entry's sequence number is the
40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // maximum value.  This should almost never be the case.
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (it->first < g_max_sequence_number)
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int sequence_number = 0;
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (std::map<int, SavedFileEntry*>::iterator it = saved_file_lru_.begin();
41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != saved_file_lru_.end();
41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       ++it) {
41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    sequence_number++;
41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (it->second->sequence_number == sequence_number)
41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SavedFileEntry* file_entry = it->second;
41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    file_entry->sequence_number = sequence_number;
41890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    UpdateSavedFileEntry(prefs, extension_id_, *file_entry);
41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    saved_file_lru_.erase(it++);
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Provide the following element as an insert hint. While optimized
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // insertion time with the following element as a hint is only supported by
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the spec in C++11, the implementations do support this.
42390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    it = saved_file_lru_.insert(
42490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        it, std::make_pair(file_entry->sequence_number, file_entry));
42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::SavedFiles::LoadSavedFileEntriesFromPreferences() {
42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<SavedFileEntry> saved_entries =
43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      GetSavedFileEntries(prefs, extension_id_);
43290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (std::vector<SavedFileEntry>::iterator it = saved_entries.begin();
43390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != saved_entries.end();
43490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       ++it) {
43590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SavedFileEntry* file_entry = new SavedFileEntry(*it);
43690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    registered_file_entries_.insert(std::make_pair(file_entry->id, file_entry));
43790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    saved_file_lru_.insert(
43890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        std::make_pair(file_entry->sequence_number, file_entry));
43990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
44090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
44190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
44390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::SetMaxSequenceNumberForTest(int max_value) {
44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  g_max_sequence_number = max_value;
44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::ClearMaxSequenceNumberForTest() {
44990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  g_max_sequence_number = kMaxSequenceNumber;
45090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
45190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
45390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::SetLruSizeForTest(int size) {
45490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  g_max_saved_file_entries = size;
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SavedFilesService::ClearLruSizeForTest() {
45990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  g_max_saved_file_entries = kMaxSavedFileEntries;
46090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
46190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
46290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace apps
463