OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/extension_change_processor.h" | 5 #include "chrome/browser/sync/glue/extension_change_processor.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "chrome/browser/chrome_thread.h" | 11 #include "chrome/browser/chrome_thread.h" |
12 #include "chrome/browser/sync/engine/syncapi.h" | 12 #include "chrome/browser/profile.h" |
13 #include "chrome/browser/sync/glue/extension_model_associator.h" | 13 #include "chrome/browser/extensions/extensions_service.h" |
| 14 #include "chrome/browser/sync/glue/extension_sync.h" |
14 #include "chrome/browser/sync/glue/extension_util.h" | 15 #include "chrome/browser/sync/glue/extension_util.h" |
| 16 #include "chrome/browser/sync/protocol/extension_specifics.pb.h" |
15 #include "chrome/common/extensions/extension.h" | 17 #include "chrome/common/extensions/extension.h" |
16 #include "chrome/common/notification_details.h" | 18 #include "chrome/common/notification_details.h" |
17 #include "chrome/common/notification_source.h" | 19 #include "chrome/common/notification_source.h" |
18 | 20 |
19 namespace browser_sync { | 21 namespace browser_sync { |
20 | 22 |
21 ExtensionChangeProcessor::ExtensionChangeProcessor( | 23 ExtensionChangeProcessor::ExtensionChangeProcessor( |
22 UnrecoverableErrorHandler* error_handler, | 24 UnrecoverableErrorHandler* error_handler) |
23 ExtensionModelAssociator* extension_model_associator) | |
24 : ChangeProcessor(error_handler), | 25 : ChangeProcessor(error_handler), |
25 extension_model_associator_(extension_model_associator), | 26 traits_(GetExtensionSyncTraits()), |
26 profile_(NULL) { | 27 profile_(NULL) { |
27 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 28 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
28 DCHECK(error_handler); | 29 DCHECK(error_handler); |
29 DCHECK(extension_model_associator_); | |
30 } | 30 } |
31 | 31 |
32 ExtensionChangeProcessor::~ExtensionChangeProcessor() { | 32 ExtensionChangeProcessor::~ExtensionChangeProcessor() { |
33 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 33 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
34 } | 34 } |
35 | 35 |
36 // TODO(akalin): We need to make sure events we receive from either | 36 // TODO(akalin): We need to make sure events we receive from either |
37 // the browser or the syncapi are done in order; this is tricky since | 37 // the browser or the syncapi are done in order; this is tricky since |
38 // some events (e.g., extension installation) are done asynchronously. | 38 // some events (e.g., extension installation) are done asynchronously. |
39 | 39 |
40 void ExtensionChangeProcessor::Observe(NotificationType type, | 40 void ExtensionChangeProcessor::Observe(NotificationType type, |
41 const NotificationSource& source, | 41 const NotificationSource& source, |
42 const NotificationDetails& details) { | 42 const NotificationDetails& details) { |
43 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 43 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
44 DCHECK(running()); | 44 DCHECK(running()); |
45 DCHECK(profile_); | 45 DCHECK(profile_); |
46 switch (type.value) { | 46 if ((type != NotificationType::EXTENSION_LOADED) && |
47 case NotificationType::EXTENSION_LOADED: | 47 (type != NotificationType::EXTENSION_UPDATE_DISABLED) && |
48 case NotificationType::EXTENSION_UPDATE_DISABLED: | 48 (type != NotificationType::EXTENSION_UNLOADED) && |
49 case NotificationType::EXTENSION_UNLOADED: | 49 (type != NotificationType::EXTENSION_UNLOADED_DISABLED)) { |
50 case NotificationType::EXTENSION_UNLOADED_DISABLED: { | 50 LOG(DFATAL) << "Received unexpected notification of type " |
51 DCHECK_EQ(Source<Profile>(source).ptr(), profile_); | 51 << type.value; |
52 Extension* extension = Details<Extension>(details).ptr(); | 52 return; |
53 CHECK(extension); | 53 } |
54 // Ignore non-syncable extensions. | 54 DCHECK_EQ(Source<Profile>(source).ptr(), profile_); |
55 if (!IsExtensionSyncable(*extension)) { | 55 const Extension* extension = Details<Extension>(details).ptr(); |
56 return; | 56 CHECK(extension); |
57 } | 57 // Ignore non-syncable extensions. |
58 const std::string& id = extension->id(); | 58 if (!IsExtensionValidAndSyncable( |
59 LOG(INFO) << "Got change notification of type " << type.value | 59 *extension, traits_.allowed_extension_types)) { |
60 << " for extension " << id; | 60 return; |
61 if (!extension_model_associator_->OnClientUpdate(id)) { | 61 } |
62 std::string error = std::string("Client update failed for ") + id; | 62 const std::string& id = extension->id(); |
63 error_handler()->OnUnrecoverableError(FROM_HERE, error); | 63 LOG(INFO) << "Got notification of type " << type.value |
64 return; | 64 << " for extension " << id; |
65 } | 65 ExtensionsService* extensions_service = |
66 break; | 66 GetExtensionsServiceFromProfile(profile_); |
| 67 // Whether an extension is loaded or not isn't an indicator of |
| 68 // whether it's installed or not; some extension actions unload and |
| 69 // then reload an extension to force listeners to update. |
| 70 bool extension_installed = |
| 71 (extensions_service->GetExtensionById(id, true) != NULL); |
| 72 if (extension_installed) { |
| 73 LOG(INFO) << "Extension " << id |
| 74 << " is installed; updating server data"; |
| 75 std::string error; |
| 76 if (!UpdateServerData(traits_, *extension, |
| 77 profile_->GetProfileSyncService(), &error)) { |
| 78 error_handler()->OnUnrecoverableError(FROM_HERE, error); |
67 } | 79 } |
68 default: | 80 } else { |
69 LOG(DFATAL) << "Received unexpected notification of type " | 81 LOG(INFO) << "Extension " << id |
70 << type.value; | 82 << " is not installed; removing server data"; |
71 break; | 83 RemoveServerData(traits_, *extension, |
| 84 profile_->GetProfileSyncService()); |
72 } | 85 } |
73 } | 86 } |
74 | 87 |
75 void ExtensionChangeProcessor::ApplyChangesFromSyncModel( | 88 void ExtensionChangeProcessor::ApplyChangesFromSyncModel( |
76 const sync_api::BaseTransaction* trans, | 89 const sync_api::BaseTransaction* trans, |
77 const sync_api::SyncManager::ChangeRecord* changes, | 90 const sync_api::SyncManager::ChangeRecord* changes, |
78 int change_count) { | 91 int change_count) { |
79 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 92 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
80 if (!running()) { | 93 if (!running()) { |
81 return; | 94 return; |
82 } | 95 } |
| 96 ExtensionsService* extensions_service = |
| 97 GetExtensionsServiceFromProfile(profile_); |
83 for (int i = 0; i < change_count; ++i) { | 98 for (int i = 0; i < change_count; ++i) { |
84 const sync_api::SyncManager::ChangeRecord& change = changes[i]; | 99 const sync_api::SyncManager::ChangeRecord& change = changes[i]; |
85 switch (change.action) { | 100 switch (change.action) { |
86 case sync_api::SyncManager::ChangeRecord::ACTION_ADD: | 101 case sync_api::SyncManager::ChangeRecord::ACTION_ADD: |
87 case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: { | 102 case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: { |
88 sync_api::ReadNode node(trans); | 103 sync_api::ReadNode node(trans); |
89 if (!node.InitByIdLookup(change.id)) { | 104 if (!node.InitByIdLookup(change.id)) { |
90 std::stringstream error; | 105 std::stringstream error; |
91 error << "Extension node lookup failed for change " << change.id | 106 error << "Extension node lookup failed for change " << change.id |
92 << " of action type " << change.action; | 107 << " of action type " << change.action; |
93 error_handler()->OnUnrecoverableError(FROM_HERE, error.str()); | 108 error_handler()->OnUnrecoverableError(FROM_HERE, error.str()); |
94 return; | 109 return; |
95 } | 110 } |
96 DCHECK_EQ(node.GetModelType(), syncable::EXTENSIONS); | 111 DCHECK_EQ(node.GetModelType(), traits_.model_type); |
97 const sync_pb::ExtensionSpecifics& specifics = | 112 const sync_pb::ExtensionSpecifics& specifics = |
98 node.GetExtensionSpecifics(); | 113 (*traits_.extension_specifics_getter)(node); |
99 if (!IsExtensionSpecificsValid(specifics)) { | 114 if (!IsExtensionSpecificsValid(specifics)) { |
100 std::string error = | 115 std::string error = |
101 std::string("Invalid server specifics: ") + | 116 std::string("Invalid server specifics: ") + |
102 ExtensionSpecificsToString(specifics); | 117 ExtensionSpecificsToString(specifics); |
103 error_handler()->OnUnrecoverableError(FROM_HERE, error); | 118 error_handler()->OnUnrecoverableError(FROM_HERE, error); |
104 return; | 119 return; |
105 } | 120 } |
106 StopObserving(); | 121 StopObserving(); |
107 extension_model_associator_->OnServerUpdate(specifics); | 122 UpdateClient(traits_, specifics, extensions_service); |
108 StartObserving(); | 123 StartObserving(); |
109 break; | 124 break; |
110 } | 125 } |
111 case sync_api::SyncManager::ChangeRecord::ACTION_DELETE: { | 126 case sync_api::SyncManager::ChangeRecord::ACTION_DELETE: { |
112 StopObserving(); | 127 sync_pb::ExtensionSpecifics specifics; |
113 if (change.specifics.HasExtension(sync_pb::extension)) { | 128 if ((*traits_.extension_specifics_entity_getter)( |
114 extension_model_associator_->OnServerRemove( | 129 change.specifics, &specifics)) { |
115 change.specifics.GetExtension(sync_pb::extension).id()); | 130 StopObserving(); |
| 131 RemoveFromClient(traits_, specifics.id(), extensions_service); |
| 132 StartObserving(); |
116 } else { | 133 } else { |
117 std::stringstream error; | 134 std::stringstream error; |
118 error << "Could not get extension ID for deleted node " | 135 error << "Could not get extension ID for deleted node " |
119 << change.id; | 136 << change.id; |
120 error_handler()->OnUnrecoverableError(FROM_HERE, error.str()); | 137 error_handler()->OnUnrecoverableError(FROM_HERE, error.str()); |
121 LOG(DFATAL) << error.str(); | 138 LOG(DFATAL) << error.str(); |
122 } | 139 } |
123 StartObserving(); | |
124 break; | 140 break; |
125 } | 141 } |
126 } | 142 } |
127 } | 143 } |
128 } | 144 } |
129 | 145 |
130 void ExtensionChangeProcessor::StartImpl(Profile* profile) { | 146 void ExtensionChangeProcessor::StartImpl(Profile* profile) { |
131 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 147 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
132 DCHECK(profile); | 148 DCHECK(profile); |
133 profile_ = profile; | 149 profile_ = profile; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 } | 181 } |
166 | 182 |
167 void ExtensionChangeProcessor::StopObserving() { | 183 void ExtensionChangeProcessor::StopObserving() { |
168 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 184 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
169 DCHECK(profile_); | 185 DCHECK(profile_); |
170 LOG(INFO) << "Unobserving all notifications"; | 186 LOG(INFO) << "Unobserving all notifications"; |
171 notification_registrar_.RemoveAll(); | 187 notification_registrar_.RemoveAll(); |
172 } | 188 } |
173 | 189 |
174 } // namespace browser_sync | 190 } // namespace browser_sync |
OLD | NEW |