1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/system/gonk/AutoMounterSetting.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,292 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "AutoMounter.h" 1.9 +#include "AutoMounterSetting.h" 1.10 + 1.11 +#include "base/message_loop.h" 1.12 +#include "jsapi.h" 1.13 +#include "mozilla/Services.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "nsDebug.h" 1.16 +#include "nsIObserverService.h" 1.17 +#include "nsCxPusher.h" 1.18 +#include "nsISettingsService.h" 1.19 +#include "nsJSUtils.h" 1.20 +#include "nsPrintfCString.h" 1.21 +#include "nsServiceManagerUtils.h" 1.22 +#include "nsString.h" 1.23 +#include "nsThreadUtils.h" 1.24 +#include "xpcpublic.h" 1.25 +#include "mozilla/Attributes.h" 1.26 + 1.27 +#undef LOG 1.28 +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AutoMounterSetting" , ## args) 1.29 +#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "AutoMounterSetting" , ## args) 1.30 + 1.31 +#define UMS_MODE "ums.mode" 1.32 +#define UMS_STATUS "ums.status" 1.33 +#define UMS_VOLUME_ENABLED_PREFIX "ums.volume." 1.34 +#define UMS_VOLUME_ENABLED_SUFFIX ".enabled" 1.35 +#define MOZSETTINGS_CHANGED "mozsettings-changed" 1.36 + 1.37 +namespace mozilla { 1.38 +namespace system { 1.39 + 1.40 +class SettingsServiceCallback MOZ_FINAL : public nsISettingsServiceCallback 1.41 +{ 1.42 +public: 1.43 + NS_DECL_THREADSAFE_ISUPPORTS 1.44 + 1.45 + SettingsServiceCallback() {} 1.46 + 1.47 + NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) 1.48 + { 1.49 + if (JSVAL_IS_INT(aResult)) { 1.50 + int32_t mode = JSVAL_TO_INT(aResult); 1.51 + SetAutoMounterMode(mode); 1.52 + } 1.53 + return NS_OK; 1.54 + } 1.55 + 1.56 + NS_IMETHOD HandleError(const nsAString& aName) 1.57 + { 1.58 + ERR("SettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); 1.59 + return NS_OK; 1.60 + } 1.61 +}; 1.62 + 1.63 +NS_IMPL_ISUPPORTS(SettingsServiceCallback, nsISettingsServiceCallback) 1.64 + 1.65 +class CheckVolumeSettingsCallback MOZ_FINAL : public nsISettingsServiceCallback 1.66 +{ 1.67 +public: 1.68 + NS_DECL_THREADSAFE_ISUPPORTS 1.69 + 1.70 + CheckVolumeSettingsCallback(const nsACString& aVolumeName) 1.71 + : mVolumeName(aVolumeName) {} 1.72 + 1.73 + NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) 1.74 + { 1.75 + if (JSVAL_IS_BOOLEAN(aResult)) { 1.76 + bool isSharingEnabled = JSVAL_TO_BOOLEAN(aResult); 1.77 + SetAutoMounterSharingMode(mVolumeName, isSharingEnabled); 1.78 + } 1.79 + return NS_OK; 1.80 + } 1.81 + 1.82 + NS_IMETHOD HandleError(const nsAString& aName) 1.83 + { 1.84 + ERR("CheckVolumeSettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); 1.85 + return NS_OK; 1.86 + } 1.87 +private: 1.88 + nsCString mVolumeName; 1.89 +}; 1.90 + 1.91 +NS_IMPL_ISUPPORTS(CheckVolumeSettingsCallback, nsISettingsServiceCallback) 1.92 + 1.93 +AutoMounterSetting::AutoMounterSetting() 1.94 + : mStatus(AUTOMOUNTER_STATUS_DISABLED) 1.95 +{ 1.96 + MOZ_ASSERT(NS_IsMainThread()); 1.97 + 1.98 + // Setup an observer to watch changes to the setting 1.99 + nsCOMPtr<nsIObserverService> observerService = 1.100 + mozilla::services::GetObserverService(); 1.101 + if (!observerService) { 1.102 + ERR("GetObserverService failed"); 1.103 + return; 1.104 + } 1.105 + nsresult rv; 1.106 + rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false); 1.107 + if (NS_FAILED(rv)) { 1.108 + ERR("AddObserver failed"); 1.109 + return; 1.110 + } 1.111 + 1.112 + // Force ums.mode to be 0 initially. We do this because settings are persisted. 1.113 + // We don't want UMS to be enabled until such time as the phone is unlocked, 1.114 + // and gaia/apps/system/js/storage.js takes care of detecting when the phone 1.115 + // becomes unlocked and changes ums.mode appropriately. 1.116 + nsCOMPtr<nsISettingsService> settingsService = 1.117 + do_GetService("@mozilla.org/settingsService;1"); 1.118 + if (!settingsService) { 1.119 + ERR("Failed to get settingsLock service!"); 1.120 + return; 1.121 + } 1.122 + nsCOMPtr<nsISettingsServiceLock> lock; 1.123 + settingsService->CreateLock(nullptr, getter_AddRefs(lock)); 1.124 + nsCOMPtr<nsISettingsServiceCallback> callback = new SettingsServiceCallback(); 1.125 + mozilla::AutoSafeJSContext cx; 1.126 + JS::Rooted<JS::Value> value(cx); 1.127 + value.setInt32(AUTOMOUNTER_DISABLE); 1.128 + lock->Set(UMS_MODE, value, callback, nullptr); 1.129 + value.setInt32(mStatus); 1.130 + lock->Set(UMS_STATUS, value, nullptr, nullptr); 1.131 +} 1.132 + 1.133 +AutoMounterSetting::~AutoMounterSetting() 1.134 +{ 1.135 + nsCOMPtr<nsIObserverService> observerService = 1.136 + mozilla::services::GetObserverService(); 1.137 + if (observerService) { 1.138 + observerService->RemoveObserver(this, MOZSETTINGS_CHANGED); 1.139 + } 1.140 +} 1.141 + 1.142 +NS_IMPL_ISUPPORTS(AutoMounterSetting, nsIObserver) 1.143 + 1.144 +const char * 1.145 +AutoMounterSetting::StatusStr(int32_t aStatus) 1.146 +{ 1.147 + switch (aStatus) { 1.148 + case AUTOMOUNTER_STATUS_DISABLED: return "Disabled"; 1.149 + case AUTOMOUNTER_STATUS_ENABLED: return "Enabled"; 1.150 + case AUTOMOUNTER_STATUS_FILES_OPEN: return "FilesOpen"; 1.151 + } 1.152 + return "??? Unknown ???"; 1.153 +} 1.154 + 1.155 +class CheckVolumeSettingsRunnable : public nsRunnable 1.156 +{ 1.157 +public: 1.158 + CheckVolumeSettingsRunnable(const nsACString& aVolumeName) 1.159 + : mVolumeName(aVolumeName) {} 1.160 + 1.161 + NS_IMETHOD Run() 1.162 + { 1.163 + MOZ_ASSERT(NS_IsMainThread()); 1.164 + nsCOMPtr<nsISettingsService> settingsService = 1.165 + do_GetService("@mozilla.org/settingsService;1"); 1.166 + NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE); 1.167 + nsCOMPtr<nsISettingsServiceLock> lock; 1.168 + settingsService->CreateLock(nullptr, getter_AddRefs(lock)); 1.169 + nsCOMPtr<nsISettingsServiceCallback> callback = 1.170 + new CheckVolumeSettingsCallback(mVolumeName); 1.171 + nsPrintfCString setting(UMS_VOLUME_ENABLED_PREFIX "%s" UMS_VOLUME_ENABLED_SUFFIX, 1.172 + mVolumeName.get()); 1.173 + lock->Get(setting.get(), callback); 1.174 + return NS_OK; 1.175 + } 1.176 + 1.177 +private: 1.178 + nsCString mVolumeName; 1.179 +}; 1.180 + 1.181 +//static 1.182 +void 1.183 +AutoMounterSetting::CheckVolumeSettings(const nsACString& aVolumeName) 1.184 +{ 1.185 + NS_DispatchToMainThread(new CheckVolumeSettingsRunnable(aVolumeName)); 1.186 +} 1.187 + 1.188 +class SetStatusRunnable : public nsRunnable 1.189 +{ 1.190 +public: 1.191 + SetStatusRunnable(int32_t aStatus) : mStatus(aStatus) {} 1.192 + 1.193 + NS_IMETHOD Run() 1.194 + { 1.195 + MOZ_ASSERT(NS_IsMainThread()); 1.196 + nsCOMPtr<nsISettingsService> settingsService = 1.197 + do_GetService("@mozilla.org/settingsService;1"); 1.198 + NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE); 1.199 + nsCOMPtr<nsISettingsServiceLock> lock; 1.200 + settingsService->CreateLock(nullptr, getter_AddRefs(lock)); 1.201 + // lock may be null if this gets called during shutdown. 1.202 + if (lock) { 1.203 + mozilla::AutoSafeJSContext cx; 1.204 + JS::Rooted<JS::Value> value(cx, JS::Int32Value(mStatus)); 1.205 + lock->Set(UMS_STATUS, value, nullptr, nullptr); 1.206 + } 1.207 + return NS_OK; 1.208 + } 1.209 + 1.210 +private: 1.211 + int32_t mStatus; 1.212 +}; 1.213 + 1.214 +//static 1.215 +void 1.216 +AutoMounterSetting::SetStatus(int32_t aStatus) 1.217 +{ 1.218 + if (aStatus != mStatus) { 1.219 + LOG("Changing status from '%s' to '%s'", 1.220 + StatusStr(mStatus), StatusStr(aStatus)); 1.221 + mStatus = aStatus; 1.222 + NS_DispatchToMainThread(new SetStatusRunnable(aStatus)); 1.223 + } 1.224 +} 1.225 + 1.226 +NS_IMETHODIMP 1.227 +AutoMounterSetting::Observe(nsISupports* aSubject, 1.228 + const char* aTopic, 1.229 + const char16_t* aData) 1.230 +{ 1.231 + if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) { 1.232 + return NS_OK; 1.233 + } 1.234 + 1.235 + // Note that this function gets called for any and all settings changes, 1.236 + // so we need to carefully check if we have the one we're interested in. 1.237 + // 1.238 + // The string that we're interested in will be a JSON string that looks like: 1.239 + // {"key":"ums.autoMount","value":true} 1.240 + 1.241 + mozilla::AutoSafeJSContext cx; 1.242 + nsDependentString dataStr(aData); 1.243 + JS::Rooted<JS::Value> val(cx); 1.244 + if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) || 1.245 + !val.isObject()) { 1.246 + return NS_OK; 1.247 + } 1.248 + JS::Rooted<JSObject*> obj(cx, &val.toObject()); 1.249 + JS::Rooted<JS::Value> key(cx); 1.250 + if (!JS_GetProperty(cx, obj, "key", &key) || 1.251 + !key.isString()) { 1.252 + return NS_OK; 1.253 + } 1.254 + 1.255 + JSString *jsKey = JS::ToString(cx, key); 1.256 + nsDependentJSString keyStr; 1.257 + if (!keyStr.init(cx, jsKey)) { 1.258 + return NS_OK; 1.259 + } 1.260 + 1.261 + JS::Rooted<JS::Value> value(cx); 1.262 + if (!JS_GetProperty(cx, obj, "value", &value)) { 1.263 + return NS_OK; 1.264 + } 1.265 + 1.266 + // Check for ums.mode changes 1.267 + if (keyStr.EqualsLiteral(UMS_MODE)) { 1.268 + if (!value.isInt32()) { 1.269 + return NS_OK; 1.270 + } 1.271 + int32_t mode = value.toInt32(); 1.272 + SetAutoMounterMode(mode); 1.273 + return NS_OK; 1.274 + } 1.275 + 1.276 + // Check for ums.volume.NAME.enabled 1.277 + if (StringBeginsWith(keyStr, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_PREFIX)) && 1.278 + StringEndsWith(keyStr, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_SUFFIX))) { 1.279 + if (!value.isBoolean()) { 1.280 + return NS_OK; 1.281 + } 1.282 + const size_t prefixLen = sizeof(UMS_VOLUME_ENABLED_PREFIX) - 1; 1.283 + const size_t suffixLen = sizeof(UMS_VOLUME_ENABLED_SUFFIX) - 1; 1.284 + nsDependentSubstring volumeName = 1.285 + Substring(keyStr, prefixLen, keyStr.Length() - prefixLen - suffixLen); 1.286 + bool isSharingEnabled = value.toBoolean(); 1.287 + SetAutoMounterSharingMode(NS_LossyConvertUTF16toASCII(volumeName), isSharingEnabled); 1.288 + return NS_OK; 1.289 + } 1.290 + 1.291 + return NS_OK; 1.292 +} 1.293 + 1.294 +} // namespace system 1.295 +} // namespace mozilla