1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/hal/gonk/GonkHal.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1480 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et ft=cpp : */ 1.6 +/* Copyright 2012 Mozilla Foundation and Mozilla contributors 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#include <ctype.h> 1.22 +#include <errno.h> 1.23 +#include <fcntl.h> 1.24 +#include <linux/android_alarm.h> 1.25 +#include <math.h> 1.26 +#include <regex.h> 1.27 +#include <stdio.h> 1.28 +#include <sys/klog.h> 1.29 +#include <sys/syscall.h> 1.30 +#include <sys/resource.h> 1.31 +#include <time.h> 1.32 +#include <asm/page.h> 1.33 + 1.34 +#include "mozilla/DebugOnly.h" 1.35 + 1.36 +#include "android/log.h" 1.37 +#include "cutils/properties.h" 1.38 +#include "hardware/hardware.h" 1.39 +#include "hardware/lights.h" 1.40 +#include "hardware_legacy/uevent.h" 1.41 +#include "hardware_legacy/vibrator.h" 1.42 +#include "hardware_legacy/power.h" 1.43 +#include "libdisplay/GonkDisplay.h" 1.44 + 1.45 +#include "base/message_loop.h" 1.46 + 1.47 +#include "Hal.h" 1.48 +#include "HalImpl.h" 1.49 +#include "mozilla/ArrayUtils.h" 1.50 +#include "mozilla/dom/battery/Constants.h" 1.51 +#include "mozilla/FileUtils.h" 1.52 +#include "mozilla/Monitor.h" 1.53 +#include "mozilla/RefPtr.h" 1.54 +#include "mozilla/Services.h" 1.55 +#include "mozilla/StaticPtr.h" 1.56 +#include "mozilla/Preferences.h" 1.57 +#include "nsAlgorithm.h" 1.58 +#include "nsPrintfCString.h" 1.59 +#include "nsIObserver.h" 1.60 +#include "nsIObserverService.h" 1.61 +#include "nsIRecoveryService.h" 1.62 +#include "nsIRunnable.h" 1.63 +#include "nsScreenManagerGonk.h" 1.64 +#include "nsThreadUtils.h" 1.65 +#include "nsThreadUtils.h" 1.66 +#include "nsIThread.h" 1.67 +#include "nsXULAppAPI.h" 1.68 +#include "OrientationObserver.h" 1.69 +#include "UeventPoller.h" 1.70 +#include <algorithm> 1.71 + 1.72 +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args) 1.73 +#define NsecPerMsec 1000000LL 1.74 +#define NsecPerSec 1000000000 1.75 + 1.76 +// The header linux/oom.h is not available in bionic libc. We 1.77 +// redefine some of its constants here. 1.78 + 1.79 +#ifndef OOM_DISABLE 1.80 +#define OOM_DISABLE (-17) 1.81 +#endif 1.82 + 1.83 +#ifndef OOM_ADJUST_MIN 1.84 +#define OOM_ADJUST_MIN (-16) 1.85 +#endif 1.86 + 1.87 +#ifndef OOM_ADJUST_MAX 1.88 +#define OOM_ADJUST_MAX 15 1.89 +#endif 1.90 + 1.91 +#ifndef OOM_SCORE_ADJ_MIN 1.92 +#define OOM_SCORE_ADJ_MIN (-1000) 1.93 +#endif 1.94 + 1.95 +#ifndef OOM_SCORE_ADJ_MAX 1.96 +#define OOM_SCORE_ADJ_MAX 1000 1.97 +#endif 1.98 + 1.99 +#ifndef BATTERY_CHARGING_ARGB 1.100 +#define BATTERY_CHARGING_ARGB 0x00FF0000 1.101 +#endif 1.102 +#ifndef BATTERY_FULL_ARGB 1.103 +#define BATTERY_FULL_ARGB 0x0000FF00 1.104 +#endif 1.105 + 1.106 +using namespace mozilla; 1.107 +using namespace mozilla::hal; 1.108 + 1.109 +namespace mozilla { 1.110 +namespace hal_impl { 1.111 + 1.112 +namespace { 1.113 + 1.114 +/** 1.115 + * This runnable runs for the lifetime of the program, once started. It's 1.116 + * responsible for "playing" vibration patterns. 1.117 + */ 1.118 +class VibratorRunnable 1.119 + : public nsIRunnable 1.120 + , public nsIObserver 1.121 +{ 1.122 +public: 1.123 + VibratorRunnable() 1.124 + : mMonitor("VibratorRunnable") 1.125 + , mIndex(0) 1.126 + { 1.127 + nsCOMPtr<nsIObserverService> os = services::GetObserverService(); 1.128 + if (!os) { 1.129 + NS_WARNING("Could not get observer service!"); 1.130 + return; 1.131 + } 1.132 + 1.133 + os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); 1.134 + } 1.135 + 1.136 + NS_DECL_THREADSAFE_ISUPPORTS 1.137 + NS_DECL_NSIRUNNABLE 1.138 + NS_DECL_NSIOBSERVER 1.139 + 1.140 + // Run on the main thread, not the vibrator thread. 1.141 + void Vibrate(const nsTArray<uint32_t> &pattern); 1.142 + void CancelVibrate(); 1.143 + 1.144 + static bool ShuttingDown() { return sShuttingDown; } 1.145 + 1.146 +private: 1.147 + Monitor mMonitor; 1.148 + 1.149 + // The currently-playing pattern. 1.150 + nsTArray<uint32_t> mPattern; 1.151 + 1.152 + // The index we're at in the currently-playing pattern. If mIndex >= 1.153 + // mPattern.Length(), then we're not currently playing anything. 1.154 + uint32_t mIndex; 1.155 + 1.156 + // Set to true in our shutdown observer. When this is true, we kill the 1.157 + // vibrator thread. 1.158 + static bool sShuttingDown; 1.159 +}; 1.160 + 1.161 +NS_IMPL_ISUPPORTS(VibratorRunnable, nsIRunnable, nsIObserver); 1.162 + 1.163 +bool VibratorRunnable::sShuttingDown = false; 1.164 + 1.165 +static StaticRefPtr<VibratorRunnable> sVibratorRunnable; 1.166 + 1.167 +NS_IMETHODIMP 1.168 +VibratorRunnable::Run() 1.169 +{ 1.170 + MonitorAutoLock lock(mMonitor); 1.171 + 1.172 + // We currently assume that mMonitor.Wait(X) waits for X milliseconds. But in 1.173 + // reality, the kernel might not switch to this thread for some time after the 1.174 + // wait expires. So there's potential for some inaccuracy here. 1.175 + // 1.176 + // This doesn't worry me too much. Note that we don't even start vibrating 1.177 + // immediately when VibratorRunnable::Vibrate is called -- we go through a 1.178 + // condvar onto another thread. Better just to be chill about small errors in 1.179 + // the timing here. 1.180 + 1.181 + while (!sShuttingDown) { 1.182 + if (mIndex < mPattern.Length()) { 1.183 + uint32_t duration = mPattern[mIndex]; 1.184 + if (mIndex % 2 == 0) { 1.185 + vibrator_on(duration); 1.186 + } 1.187 + mIndex++; 1.188 + mMonitor.Wait(PR_MillisecondsToInterval(duration)); 1.189 + } 1.190 + else { 1.191 + mMonitor.Wait(); 1.192 + } 1.193 + } 1.194 + sVibratorRunnable = nullptr; 1.195 + return NS_OK; 1.196 +} 1.197 + 1.198 +NS_IMETHODIMP 1.199 +VibratorRunnable::Observe(nsISupports *subject, const char *topic, 1.200 + const char16_t *data) 1.201 +{ 1.202 + MOZ_ASSERT(strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); 1.203 + MonitorAutoLock lock(mMonitor); 1.204 + sShuttingDown = true; 1.205 + mMonitor.Notify(); 1.206 + 1.207 + return NS_OK; 1.208 +} 1.209 + 1.210 +void 1.211 +VibratorRunnable::Vibrate(const nsTArray<uint32_t> &pattern) 1.212 +{ 1.213 + MonitorAutoLock lock(mMonitor); 1.214 + mPattern = pattern; 1.215 + mIndex = 0; 1.216 + mMonitor.Notify(); 1.217 +} 1.218 + 1.219 +void 1.220 +VibratorRunnable::CancelVibrate() 1.221 +{ 1.222 + MonitorAutoLock lock(mMonitor); 1.223 + mPattern.Clear(); 1.224 + mPattern.AppendElement(0); 1.225 + mIndex = 0; 1.226 + mMonitor.Notify(); 1.227 +} 1.228 + 1.229 +void 1.230 +EnsureVibratorThreadInitialized() 1.231 +{ 1.232 + if (sVibratorRunnable) { 1.233 + return; 1.234 + } 1.235 + 1.236 + sVibratorRunnable = new VibratorRunnable(); 1.237 + nsCOMPtr<nsIThread> thread; 1.238 + NS_NewThread(getter_AddRefs(thread), sVibratorRunnable); 1.239 +} 1.240 + 1.241 +} // anonymous namespace 1.242 + 1.243 +void 1.244 +Vibrate(const nsTArray<uint32_t> &pattern, const hal::WindowIdentifier &) 1.245 +{ 1.246 + MOZ_ASSERT(NS_IsMainThread()); 1.247 + if (VibratorRunnable::ShuttingDown()) { 1.248 + return; 1.249 + } 1.250 + EnsureVibratorThreadInitialized(); 1.251 + sVibratorRunnable->Vibrate(pattern); 1.252 +} 1.253 + 1.254 +void 1.255 +CancelVibrate(const hal::WindowIdentifier &) 1.256 +{ 1.257 + MOZ_ASSERT(NS_IsMainThread()); 1.258 + if (VibratorRunnable::ShuttingDown()) { 1.259 + return; 1.260 + } 1.261 + EnsureVibratorThreadInitialized(); 1.262 + sVibratorRunnable->CancelVibrate(); 1.263 +} 1.264 + 1.265 +namespace { 1.266 + 1.267 +class BatteryUpdater : public nsRunnable { 1.268 +public: 1.269 + NS_IMETHOD Run() 1.270 + { 1.271 + hal::BatteryInformation info; 1.272 + hal_impl::GetCurrentBatteryInformation(&info); 1.273 + 1.274 + // Control the battery indicator (led light) here using BatteryInformation 1.275 + // we just retrieved. 1.276 + uint32_t color = 0; // Format: 0x00rrggbb. 1.277 + if (info.charging() && (info.level() == 1)) { 1.278 + // Charging and battery full. 1.279 + color = BATTERY_FULL_ARGB; 1.280 + } else if (info.charging() && (info.level() < 1)) { 1.281 + // Charging but not full. 1.282 + color = BATTERY_CHARGING_ARGB; 1.283 + } // else turn off battery indicator. 1.284 + 1.285 + hal::LightConfiguration aConfig(hal::eHalLightID_Battery, 1.286 + hal::eHalLightMode_User, 1.287 + hal::eHalLightFlash_None, 1.288 + 0, 1.289 + 0, 1.290 + color); 1.291 + hal_impl::SetLight(hal::eHalLightID_Battery, aConfig); 1.292 + 1.293 + hal::NotifyBatteryChange(info); 1.294 + return NS_OK; 1.295 + } 1.296 +}; 1.297 + 1.298 +} // anonymous namespace 1.299 + 1.300 +class BatteryObserver : public IUeventObserver 1.301 +{ 1.302 +public: 1.303 + NS_INLINE_DECL_REFCOUNTING(BatteryObserver) 1.304 + 1.305 + BatteryObserver() 1.306 + :mUpdater(new BatteryUpdater()) 1.307 + { 1.308 + } 1.309 + 1.310 + virtual void Notify(const NetlinkEvent &aEvent) 1.311 + { 1.312 + // this will run on IO thread 1.313 + NetlinkEvent *event = const_cast<NetlinkEvent*>(&aEvent); 1.314 + const char *subsystem = event->getSubsystem(); 1.315 + // e.g. DEVPATH=/devices/platform/sec-battery/power_supply/battery 1.316 + const char *devpath = event->findParam("DEVPATH"); 1.317 + if (strcmp(subsystem, "power_supply") == 0 && 1.318 + strstr(devpath, "battery")) { 1.319 + // aEvent will be valid only in this method. 1.320 + NS_DispatchToMainThread(mUpdater); 1.321 + } 1.322 + } 1.323 + 1.324 +private: 1.325 + nsRefPtr<BatteryUpdater> mUpdater; 1.326 +}; 1.327 + 1.328 +// sBatteryObserver is owned by the IO thread. Only the IO thread may 1.329 +// create or destroy it. 1.330 +static StaticRefPtr<BatteryObserver> sBatteryObserver; 1.331 + 1.332 +static void 1.333 +RegisterBatteryObserverIOThread() 1.334 +{ 1.335 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.336 + MOZ_ASSERT(!sBatteryObserver); 1.337 + 1.338 + sBatteryObserver = new BatteryObserver(); 1.339 + RegisterUeventListener(sBatteryObserver); 1.340 +} 1.341 + 1.342 +void 1.343 +EnableBatteryNotifications() 1.344 +{ 1.345 + XRE_GetIOMessageLoop()->PostTask( 1.346 + FROM_HERE, 1.347 + NewRunnableFunction(RegisterBatteryObserverIOThread)); 1.348 +} 1.349 + 1.350 +static void 1.351 +UnregisterBatteryObserverIOThread() 1.352 +{ 1.353 + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); 1.354 + MOZ_ASSERT(sBatteryObserver); 1.355 + 1.356 + UnregisterUeventListener(sBatteryObserver); 1.357 + sBatteryObserver = nullptr; 1.358 +} 1.359 + 1.360 +void 1.361 +DisableBatteryNotifications() 1.362 +{ 1.363 + XRE_GetIOMessageLoop()->PostTask( 1.364 + FROM_HERE, 1.365 + NewRunnableFunction(UnregisterBatteryObserverIOThread)); 1.366 +} 1.367 + 1.368 +static bool 1.369 +GetCurrentBatteryCharge(int* aCharge) 1.370 +{ 1.371 + bool success = ReadSysFile("/sys/class/power_supply/battery/capacity", 1.372 + aCharge); 1.373 + if (!success) { 1.374 + return false; 1.375 + } 1.376 + 1.377 + #ifdef DEBUG 1.378 + if ((*aCharge < 0) || (*aCharge > 100)) { 1.379 + HAL_LOG(("charge level contains unknown value: %d", *aCharge)); 1.380 + } 1.381 + #endif 1.382 + 1.383 + return (*aCharge >= 0) && (*aCharge <= 100); 1.384 +} 1.385 + 1.386 +static bool 1.387 +GetCurrentBatteryCharging(int* aCharging) 1.388 +{ 1.389 + static const int BATTERY_NOT_CHARGING = 0; 1.390 + static const int BATTERY_CHARGING_USB = 1; 1.391 + static const int BATTERY_CHARGING_AC = 2; 1.392 + 1.393 + // Generic device support 1.394 + 1.395 + int chargingSrc; 1.396 + bool success = 1.397 + ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc); 1.398 + 1.399 + if (success) { 1.400 + #ifdef DEBUG 1.401 + if (chargingSrc != BATTERY_NOT_CHARGING && 1.402 + chargingSrc != BATTERY_CHARGING_USB && 1.403 + chargingSrc != BATTERY_CHARGING_AC) { 1.404 + HAL_LOG(("charging_source contained unknown value: %d", chargingSrc)); 1.405 + } 1.406 + #endif 1.407 + 1.408 + *aCharging = (chargingSrc == BATTERY_CHARGING_USB || 1.409 + chargingSrc == BATTERY_CHARGING_AC); 1.410 + return true; 1.411 + } 1.412 + 1.413 + // Otoro device support 1.414 + 1.415 + char chargingSrcString[16]; 1.416 + 1.417 + success = ReadSysFile("/sys/class/power_supply/battery/status", 1.418 + chargingSrcString, sizeof(chargingSrcString)); 1.419 + if (success) { 1.420 + *aCharging = strcmp(chargingSrcString, "Charging") == 0 || 1.421 + strcmp(chargingSrcString, "Full") == 0; 1.422 + return true; 1.423 + } 1.424 + 1.425 + return false; 1.426 +} 1.427 + 1.428 +void 1.429 +GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo) 1.430 +{ 1.431 + int charge; 1.432 + 1.433 + if (GetCurrentBatteryCharge(&charge)) { 1.434 + aBatteryInfo->level() = (double)charge / 100.0; 1.435 + } else { 1.436 + aBatteryInfo->level() = dom::battery::kDefaultLevel; 1.437 + } 1.438 + 1.439 + int charging; 1.440 + 1.441 + if (GetCurrentBatteryCharging(&charging)) { 1.442 + aBatteryInfo->charging() = charging; 1.443 + } else { 1.444 + aBatteryInfo->charging() = true; 1.445 + } 1.446 + 1.447 + if (!aBatteryInfo->charging() || (aBatteryInfo->level() < 1.0)) { 1.448 + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; 1.449 + } else { 1.450 + aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime; 1.451 + } 1.452 +} 1.453 + 1.454 +namespace { 1.455 + 1.456 +/** 1.457 + * RAII class to help us remember to close file descriptors. 1.458 + */ 1.459 +const char *wakeLockFilename = "/sys/power/wake_lock"; 1.460 +const char *wakeUnlockFilename = "/sys/power/wake_unlock"; 1.461 + 1.462 +template<ssize_t n> 1.463 +bool ReadFromFile(const char *filename, char (&buf)[n]) 1.464 +{ 1.465 + int fd = open(filename, O_RDONLY); 1.466 + ScopedClose autoClose(fd); 1.467 + if (fd < 0) { 1.468 + HAL_LOG(("Unable to open file %s.", filename)); 1.469 + return false; 1.470 + } 1.471 + 1.472 + ssize_t numRead = read(fd, buf, n); 1.473 + if (numRead < 0) { 1.474 + HAL_LOG(("Error reading from file %s.", filename)); 1.475 + return false; 1.476 + } 1.477 + 1.478 + buf[std::min(numRead, n - 1)] = '\0'; 1.479 + return true; 1.480 +} 1.481 + 1.482 +bool WriteToFile(const char *filename, const char *toWrite) 1.483 +{ 1.484 + int fd = open(filename, O_WRONLY); 1.485 + ScopedClose autoClose(fd); 1.486 + if (fd < 0) { 1.487 + HAL_LOG(("Unable to open file %s.", filename)); 1.488 + return false; 1.489 + } 1.490 + 1.491 + if (write(fd, toWrite, strlen(toWrite)) < 0) { 1.492 + HAL_LOG(("Unable to write to file %s.", filename)); 1.493 + return false; 1.494 + } 1.495 + 1.496 + return true; 1.497 +} 1.498 + 1.499 +// We can write to screenEnabledFilename to enable/disable the screen, but when 1.500 +// we read, we always get "mem"! So we have to keep track ourselves whether 1.501 +// the screen is on or not. 1.502 +bool sScreenEnabled = true; 1.503 + 1.504 +// We can read wakeLockFilename to find out whether the cpu wake lock 1.505 +// is already acquired, but reading and parsing it is a lot more work 1.506 +// than tracking it ourselves, and it won't be accurate anyway (kernel 1.507 +// internal wake locks aren't counted here.) 1.508 +bool sCpuSleepAllowed = true; 1.509 + 1.510 +// Some CPU wake locks may be acquired internally in HAL. We use a counter to 1.511 +// keep track of these needs. Note we have to hold |sInternalLockCpuMonitor| 1.512 +// when reading or writing this variable to ensure thread-safe. 1.513 +int32_t sInternalLockCpuCount = 0; 1.514 + 1.515 +} // anonymous namespace 1.516 + 1.517 +bool 1.518 +GetScreenEnabled() 1.519 +{ 1.520 + return sScreenEnabled; 1.521 +} 1.522 + 1.523 +void 1.524 +SetScreenEnabled(bool enabled) 1.525 +{ 1.526 + GetGonkDisplay()->SetEnabled(enabled); 1.527 + sScreenEnabled = enabled; 1.528 +} 1.529 + 1.530 +double 1.531 +GetScreenBrightness() 1.532 +{ 1.533 + hal::LightConfiguration aConfig; 1.534 + hal::LightType light = hal::eHalLightID_Backlight; 1.535 + 1.536 + hal::GetLight(light, &aConfig); 1.537 + // backlight is brightness only, so using one of the RGB elements as value. 1.538 + int brightness = aConfig.color() & 0xFF; 1.539 + return brightness / 255.0; 1.540 +} 1.541 + 1.542 +void 1.543 +SetScreenBrightness(double brightness) 1.544 +{ 1.545 + // Don't use De Morgan's law to push the ! into this expression; we want to 1.546 + // catch NaN too. 1.547 + if (!(0 <= brightness && brightness <= 1)) { 1.548 + HAL_LOG(("SetScreenBrightness: Dropping illegal brightness %f.", 1.549 + brightness)); 1.550 + return; 1.551 + } 1.552 + 1.553 + // Convert the value in [0, 1] to an int between 0 and 255 and convert to a color 1.554 + // note that the high byte is FF, corresponding to the alpha channel. 1.555 + int val = static_cast<int>(round(brightness * 255)); 1.556 + uint32_t color = (0xff<<24) + (val<<16) + (val<<8) + val; 1.557 + 1.558 + hal::LightConfiguration aConfig; 1.559 + aConfig.mode() = hal::eHalLightMode_User; 1.560 + aConfig.flash() = hal::eHalLightFlash_None; 1.561 + aConfig.flashOnMS() = aConfig.flashOffMS() = 0; 1.562 + aConfig.color() = color; 1.563 + hal::SetLight(hal::eHalLightID_Backlight, aConfig); 1.564 + hal::SetLight(hal::eHalLightID_Buttons, aConfig); 1.565 +} 1.566 + 1.567 +static Monitor* sInternalLockCpuMonitor = nullptr; 1.568 + 1.569 +static void 1.570 +UpdateCpuSleepState() 1.571 +{ 1.572 + sInternalLockCpuMonitor->AssertCurrentThreadOwns(); 1.573 + bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount; 1.574 + WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko"); 1.575 +} 1.576 + 1.577 +static void 1.578 +InternalLockCpu() { 1.579 + MonitorAutoLock monitor(*sInternalLockCpuMonitor); 1.580 + ++sInternalLockCpuCount; 1.581 + UpdateCpuSleepState(); 1.582 +} 1.583 + 1.584 +static void 1.585 +InternalUnlockCpu() { 1.586 + MonitorAutoLock monitor(*sInternalLockCpuMonitor); 1.587 + --sInternalLockCpuCount; 1.588 + UpdateCpuSleepState(); 1.589 +} 1.590 + 1.591 +bool 1.592 +GetCpuSleepAllowed() 1.593 +{ 1.594 + return sCpuSleepAllowed; 1.595 +} 1.596 + 1.597 +void 1.598 +SetCpuSleepAllowed(bool aAllowed) 1.599 +{ 1.600 + MonitorAutoLock monitor(*sInternalLockCpuMonitor); 1.601 + sCpuSleepAllowed = aAllowed; 1.602 + UpdateCpuSleepState(); 1.603 +} 1.604 + 1.605 +static light_device_t* sLights[hal::eHalLightID_Count]; // will be initialized to nullptr 1.606 + 1.607 +light_device_t* GetDevice(hw_module_t* module, char const* name) 1.608 +{ 1.609 + int err; 1.610 + hw_device_t* device; 1.611 + err = module->methods->open(module, name, &device); 1.612 + if (err == 0) { 1.613 + return (light_device_t*)device; 1.614 + } else { 1.615 + return nullptr; 1.616 + } 1.617 +} 1.618 + 1.619 +void 1.620 +InitLights() 1.621 +{ 1.622 + // assume that if backlight is nullptr, nothing has been set yet 1.623 + // if this is not true, the initialization will occur everytime a light is read or set! 1.624 + if (!sLights[hal::eHalLightID_Backlight]) { 1.625 + int err; 1.626 + hw_module_t* module; 1.627 + 1.628 + err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); 1.629 + if (err == 0) { 1.630 + sLights[hal::eHalLightID_Backlight] 1.631 + = GetDevice(module, LIGHT_ID_BACKLIGHT); 1.632 + sLights[hal::eHalLightID_Keyboard] 1.633 + = GetDevice(module, LIGHT_ID_KEYBOARD); 1.634 + sLights[hal::eHalLightID_Buttons] 1.635 + = GetDevice(module, LIGHT_ID_BUTTONS); 1.636 + sLights[hal::eHalLightID_Battery] 1.637 + = GetDevice(module, LIGHT_ID_BATTERY); 1.638 + sLights[hal::eHalLightID_Notifications] 1.639 + = GetDevice(module, LIGHT_ID_NOTIFICATIONS); 1.640 + sLights[hal::eHalLightID_Attention] 1.641 + = GetDevice(module, LIGHT_ID_ATTENTION); 1.642 + sLights[hal::eHalLightID_Bluetooth] 1.643 + = GetDevice(module, LIGHT_ID_BLUETOOTH); 1.644 + sLights[hal::eHalLightID_Wifi] 1.645 + = GetDevice(module, LIGHT_ID_WIFI); 1.646 + } 1.647 + } 1.648 +} 1.649 + 1.650 +/** 1.651 + * The state last set for the lights until liblights supports 1.652 + * getting the light state. 1.653 + */ 1.654 +static light_state_t sStoredLightState[hal::eHalLightID_Count]; 1.655 + 1.656 +bool 1.657 +SetLight(hal::LightType light, const hal::LightConfiguration& aConfig) 1.658 +{ 1.659 + light_state_t state; 1.660 + 1.661 + InitLights(); 1.662 + 1.663 + if (light < 0 || light >= hal::eHalLightID_Count || 1.664 + sLights[light] == nullptr) { 1.665 + return false; 1.666 + } 1.667 + 1.668 + memset(&state, 0, sizeof(light_state_t)); 1.669 + state.color = aConfig.color(); 1.670 + state.flashMode = aConfig.flash(); 1.671 + state.flashOnMS = aConfig.flashOnMS(); 1.672 + state.flashOffMS = aConfig.flashOffMS(); 1.673 + state.brightnessMode = aConfig.mode(); 1.674 + 1.675 + sLights[light]->set_light(sLights[light], &state); 1.676 + sStoredLightState[light] = state; 1.677 + return true; 1.678 +} 1.679 + 1.680 +bool 1.681 +GetLight(hal::LightType light, hal::LightConfiguration* aConfig) 1.682 +{ 1.683 + light_state_t state; 1.684 + 1.685 +#ifdef HAVEGETLIGHT 1.686 + InitLights(); 1.687 +#endif 1.688 + 1.689 + if (light < 0 || light >= hal::eHalLightID_Count || 1.690 + sLights[light] == nullptr) { 1.691 + return false; 1.692 + } 1.693 + 1.694 + memset(&state, 0, sizeof(light_state_t)); 1.695 + 1.696 +#ifdef HAVEGETLIGHT 1.697 + sLights[light]->get_light(sLights[light], &state); 1.698 +#else 1.699 + state = sStoredLightState[light]; 1.700 +#endif 1.701 + 1.702 + aConfig->light() = light; 1.703 + aConfig->color() = state.color; 1.704 + aConfig->flash() = hal::FlashMode(state.flashMode); 1.705 + aConfig->flashOnMS() = state.flashOnMS; 1.706 + aConfig->flashOffMS() = state.flashOffMS; 1.707 + aConfig->mode() = hal::LightMode(state.brightnessMode); 1.708 + 1.709 + return true; 1.710 +} 1.711 + 1.712 +void 1.713 +AdjustSystemClock(int64_t aDeltaMilliseconds) 1.714 +{ 1.715 + int fd; 1.716 + struct timespec now; 1.717 + 1.718 + if (aDeltaMilliseconds == 0) { 1.719 + return; 1.720 + } 1.721 + 1.722 + // Preventing context switch before setting system clock 1.723 + sched_yield(); 1.724 + clock_gettime(CLOCK_REALTIME, &now); 1.725 + now.tv_sec += (time_t)(aDeltaMilliseconds / 1000LL); 1.726 + now.tv_nsec += (long)((aDeltaMilliseconds % 1000LL) * NsecPerMsec); 1.727 + if (now.tv_nsec >= NsecPerSec) { 1.728 + now.tv_sec += 1; 1.729 + now.tv_nsec -= NsecPerSec; 1.730 + } 1.731 + 1.732 + if (now.tv_nsec < 0) { 1.733 + now.tv_nsec += NsecPerSec; 1.734 + now.tv_sec -= 1; 1.735 + } 1.736 + 1.737 + do { 1.738 + fd = open("/dev/alarm", O_RDWR); 1.739 + } while (fd == -1 && errno == EINTR); 1.740 + ScopedClose autoClose(fd); 1.741 + if (fd < 0) { 1.742 + HAL_LOG(("Failed to open /dev/alarm: %s", strerror(errno))); 1.743 + return; 1.744 + } 1.745 + 1.746 + if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) { 1.747 + HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno))); 1.748 + } 1.749 + 1.750 + hal::NotifySystemClockChange(aDeltaMilliseconds); 1.751 +} 1.752 + 1.753 +int32_t 1.754 +GetTimezoneOffset() 1.755 +{ 1.756 + PRExplodedTime prTime; 1.757 + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime); 1.758 + 1.759 + // Daylight saving time (DST) will be taken into account. 1.760 + int32_t offset = prTime.tm_params.tp_gmt_offset; 1.761 + offset += prTime.tm_params.tp_dst_offset; 1.762 + 1.763 + // Returns the timezone offset relative to UTC in minutes. 1.764 + return -(offset / 60); 1.765 +} 1.766 + 1.767 +static int32_t sKernelTimezoneOffset = 0; 1.768 + 1.769 +static void 1.770 +UpdateKernelTimezone(int32_t timezoneOffset) 1.771 +{ 1.772 + if (sKernelTimezoneOffset == timezoneOffset) { 1.773 + return; 1.774 + } 1.775 + 1.776 + // Tell the kernel about the new time zone as well, so that FAT filesystems 1.777 + // will get local timestamps rather than UTC timestamps. 1.778 + // 1.779 + // We assume that /init.rc has a sysclktz entry so that settimeofday has 1.780 + // already been called once before we call it (there is a side-effect in 1.781 + // the kernel the very first time settimeofday is called where it does some 1.782 + // special processing if you only set the timezone). 1.783 + struct timezone tz; 1.784 + memset(&tz, 0, sizeof(tz)); 1.785 + tz.tz_minuteswest = timezoneOffset; 1.786 + settimeofday(nullptr, &tz); 1.787 + sKernelTimezoneOffset = timezoneOffset; 1.788 +} 1.789 + 1.790 +void 1.791 +SetTimezone(const nsCString& aTimezoneSpec) 1.792 +{ 1.793 + if (aTimezoneSpec.Equals(GetTimezone())) { 1.794 + // Even though the timezone hasn't changed, we still need to tell the 1.795 + // kernel what the current timezone is. The timezone is persisted in 1.796 + // a property and doesn't change across reboots, but the kernel still 1.797 + // needs to be updated on every boot. 1.798 + UpdateKernelTimezone(GetTimezoneOffset()); 1.799 + return; 1.800 + } 1.801 + 1.802 + int32_t oldTimezoneOffsetMinutes = GetTimezoneOffset(); 1.803 + property_set("persist.sys.timezone", aTimezoneSpec.get()); 1.804 + // This function is automatically called by the other time conversion 1.805 + // functions that depend on the timezone. To be safe, we call it manually. 1.806 + tzset(); 1.807 + int32_t newTimezoneOffsetMinutes = GetTimezoneOffset(); 1.808 + UpdateKernelTimezone(newTimezoneOffsetMinutes); 1.809 + hal::NotifySystemTimezoneChange( 1.810 + hal::SystemTimezoneChangeInformation( 1.811 + oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes)); 1.812 +} 1.813 + 1.814 +nsCString 1.815 +GetTimezone() 1.816 +{ 1.817 + char timezone[32]; 1.818 + property_get("persist.sys.timezone", timezone, ""); 1.819 + return nsCString(timezone); 1.820 +} 1.821 + 1.822 +void 1.823 +EnableSystemClockChangeNotifications() 1.824 +{ 1.825 +} 1.826 + 1.827 +void 1.828 +DisableSystemClockChangeNotifications() 1.829 +{ 1.830 +} 1.831 + 1.832 +void 1.833 +EnableSystemTimezoneChangeNotifications() 1.834 +{ 1.835 +} 1.836 + 1.837 +void 1.838 +DisableSystemTimezoneChangeNotifications() 1.839 +{ 1.840 +} 1.841 + 1.842 +// Nothing to do here. Gonk widgetry always listens for screen 1.843 +// orientation changes. 1.844 +void 1.845 +EnableScreenConfigurationNotifications() 1.846 +{ 1.847 +} 1.848 + 1.849 +void 1.850 +DisableScreenConfigurationNotifications() 1.851 +{ 1.852 +} 1.853 + 1.854 +void 1.855 +GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration) 1.856 +{ 1.857 + *aScreenConfiguration = nsScreenGonk::GetConfiguration(); 1.858 +} 1.859 + 1.860 +bool 1.861 +LockScreenOrientation(const dom::ScreenOrientation& aOrientation) 1.862 +{ 1.863 + return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation); 1.864 +} 1.865 + 1.866 +void 1.867 +UnlockScreenOrientation() 1.868 +{ 1.869 + OrientationObserver::GetInstance()->UnlockScreenOrientation(); 1.870 +} 1.871 + 1.872 +// This thread will wait for the alarm firing by a blocking IO. 1.873 +static pthread_t sAlarmFireWatcherThread; 1.874 + 1.875 +// If |sAlarmData| is non-null, it's owned by the alarm-watcher thread. 1.876 +struct AlarmData { 1.877 +public: 1.878 + AlarmData(int aFd) : mFd(aFd), 1.879 + mGeneration(sNextGeneration++), 1.880 + mShuttingDown(false) {} 1.881 + ScopedClose mFd; 1.882 + int mGeneration; 1.883 + bool mShuttingDown; 1.884 + 1.885 + static int sNextGeneration; 1.886 + 1.887 +}; 1.888 + 1.889 +int AlarmData::sNextGeneration = 0; 1.890 + 1.891 +AlarmData* sAlarmData = nullptr; 1.892 + 1.893 +class AlarmFiredEvent : public nsRunnable { 1.894 +public: 1.895 + AlarmFiredEvent(int aGeneration) : mGeneration(aGeneration) {} 1.896 + 1.897 + NS_IMETHOD Run() { 1.898 + // Guard against spurious notifications caused by an alarm firing 1.899 + // concurrently with it being disabled. 1.900 + if (sAlarmData && !sAlarmData->mShuttingDown && 1.901 + mGeneration == sAlarmData->mGeneration) { 1.902 + hal::NotifyAlarmFired(); 1.903 + } 1.904 + // The fired alarm event has been delivered to the observer (if needed); 1.905 + // we can now release a CPU wake lock. 1.906 + InternalUnlockCpu(); 1.907 + return NS_OK; 1.908 + } 1.909 + 1.910 +private: 1.911 + int mGeneration; 1.912 +}; 1.913 + 1.914 +// Runs on alarm-watcher thread. 1.915 +static void 1.916 +DestroyAlarmData(void* aData) 1.917 +{ 1.918 + AlarmData* alarmData = static_cast<AlarmData*>(aData); 1.919 + delete alarmData; 1.920 +} 1.921 + 1.922 +// Runs on alarm-watcher thread. 1.923 +void ShutDownAlarm(int aSigno) 1.924 +{ 1.925 + if (aSigno == SIGUSR1 && sAlarmData) { 1.926 + sAlarmData->mShuttingDown = true; 1.927 + } 1.928 + return; 1.929 +} 1.930 + 1.931 +static void* 1.932 +WaitForAlarm(void* aData) 1.933 +{ 1.934 + pthread_cleanup_push(DestroyAlarmData, aData); 1.935 + 1.936 + AlarmData* alarmData = static_cast<AlarmData*>(aData); 1.937 + 1.938 + while (!alarmData->mShuttingDown) { 1.939 + int alarmTypeFlags = 0; 1.940 + 1.941 + // ALARM_WAIT apparently will block even if an alarm hasn't been 1.942 + // programmed, although this behavior doesn't seem to be 1.943 + // documented. We rely on that here to avoid spinning the CPU 1.944 + // while awaiting an alarm to be programmed. 1.945 + do { 1.946 + alarmTypeFlags = ioctl(alarmData->mFd, ANDROID_ALARM_WAIT); 1.947 + } while (alarmTypeFlags < 0 && errno == EINTR && 1.948 + !alarmData->mShuttingDown); 1.949 + 1.950 + if (!alarmData->mShuttingDown && alarmTypeFlags >= 0 && 1.951 + (alarmTypeFlags & ANDROID_ALARM_RTC_WAKEUP_MASK)) { 1.952 + // To make sure the observer can get the alarm firing notification 1.953 + // *on time* (the system won't sleep during the process in any way), 1.954 + // we need to acquire a CPU wake lock before firing the alarm event. 1.955 + InternalLockCpu(); 1.956 + nsRefPtr<AlarmFiredEvent> event = 1.957 + new AlarmFiredEvent(alarmData->mGeneration); 1.958 + NS_DispatchToMainThread(event); 1.959 + } 1.960 + } 1.961 + 1.962 + pthread_cleanup_pop(1); 1.963 + return nullptr; 1.964 +} 1.965 + 1.966 +bool 1.967 +EnableAlarm() 1.968 +{ 1.969 + MOZ_ASSERT(!sAlarmData); 1.970 + 1.971 + int alarmFd = open("/dev/alarm", O_RDWR); 1.972 + if (alarmFd < 0) { 1.973 + HAL_LOG(("Failed to open alarm device: %s.", strerror(errno))); 1.974 + return false; 1.975 + } 1.976 + 1.977 + nsAutoPtr<AlarmData> alarmData(new AlarmData(alarmFd)); 1.978 + 1.979 + struct sigaction actions; 1.980 + memset(&actions, 0, sizeof(actions)); 1.981 + sigemptyset(&actions.sa_mask); 1.982 + actions.sa_flags = 0; 1.983 + actions.sa_handler = ShutDownAlarm; 1.984 + if (sigaction(SIGUSR1, &actions, nullptr)) { 1.985 + HAL_LOG(("Failed to set SIGUSR1 signal for alarm-watcher thread.")); 1.986 + return false; 1.987 + } 1.988 + 1.989 + pthread_attr_t attr; 1.990 + pthread_attr_init(&attr); 1.991 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 1.992 + 1.993 + // Initialize the monitor for internally locking CPU to ensure thread-safe 1.994 + // before running the alarm-watcher thread. 1.995 + sInternalLockCpuMonitor = new Monitor("sInternalLockCpuMonitor"); 1.996 + int status = pthread_create(&sAlarmFireWatcherThread, &attr, WaitForAlarm, 1.997 + alarmData.get()); 1.998 + if (status) { 1.999 + alarmData = nullptr; 1.1000 + delete sInternalLockCpuMonitor; 1.1001 + HAL_LOG(("Failed to create alarm-watcher thread. Status: %d.", status)); 1.1002 + return false; 1.1003 + } 1.1004 + 1.1005 + pthread_attr_destroy(&attr); 1.1006 + 1.1007 + // The thread owns this now. We only hold a pointer. 1.1008 + sAlarmData = alarmData.forget(); 1.1009 + return true; 1.1010 +} 1.1011 + 1.1012 +void 1.1013 +DisableAlarm() 1.1014 +{ 1.1015 + MOZ_ASSERT(sAlarmData); 1.1016 + 1.1017 + // NB: this must happen-before the thread cancellation. 1.1018 + sAlarmData = nullptr; 1.1019 + 1.1020 + // The cancel will interrupt the thread and destroy it, freeing the 1.1021 + // data pointed at by sAlarmData. 1.1022 + DebugOnly<int> err = pthread_kill(sAlarmFireWatcherThread, SIGUSR1); 1.1023 + MOZ_ASSERT(!err); 1.1024 + 1.1025 + delete sInternalLockCpuMonitor; 1.1026 +} 1.1027 + 1.1028 +bool 1.1029 +SetAlarm(int32_t aSeconds, int32_t aNanoseconds) 1.1030 +{ 1.1031 + if (!sAlarmData) { 1.1032 + HAL_LOG(("We should have enabled the alarm.")); 1.1033 + return false; 1.1034 + } 1.1035 + 1.1036 + struct timespec ts; 1.1037 + ts.tv_sec = aSeconds; 1.1038 + ts.tv_nsec = aNanoseconds; 1.1039 + 1.1040 + // Currently we only support RTC wakeup alarm type. 1.1041 + const int result = ioctl(sAlarmData->mFd, 1.1042 + ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP), &ts); 1.1043 + 1.1044 + if (result < 0) { 1.1045 + HAL_LOG(("Unable to set alarm: %s.", strerror(errno))); 1.1046 + return false; 1.1047 + } 1.1048 + 1.1049 + return true; 1.1050 +} 1.1051 + 1.1052 +static int 1.1053 +OomAdjOfOomScoreAdj(int aOomScoreAdj) 1.1054 +{ 1.1055 + // Convert OOM adjustment from the domain of /proc/<pid>/oom_score_adj 1.1056 + // to the domain of /proc/<pid>/oom_adj. 1.1057 + 1.1058 + int adj; 1.1059 + 1.1060 + if (aOomScoreAdj < 0) { 1.1061 + adj = (OOM_DISABLE * aOomScoreAdj) / OOM_SCORE_ADJ_MIN; 1.1062 + } else { 1.1063 + adj = (OOM_ADJUST_MAX * aOomScoreAdj) / OOM_SCORE_ADJ_MAX; 1.1064 + } 1.1065 + 1.1066 + return adj; 1.1067 +} 1.1068 + 1.1069 +static void 1.1070 +RoundOomScoreAdjUpWithBackroundLRU(int& aOomScoreAdj, uint32_t aBackgroundLRU) 1.1071 +{ 1.1072 + // We want to add minimum value to round OomScoreAdj up according to 1.1073 + // the steps by aBackgroundLRU. 1.1074 + aOomScoreAdj += 1.1075 + ceil(((float)OOM_SCORE_ADJ_MAX / OOM_ADJUST_MAX) * aBackgroundLRU); 1.1076 +} 1.1077 + 1.1078 +#define OOM_LOG(level, args...) __android_log_print(level, "OomLogger", ##args) 1.1079 +class OomVictimLogger MOZ_FINAL 1.1080 + : public nsIObserver 1.1081 +{ 1.1082 +public: 1.1083 + OomVictimLogger() 1.1084 + : mLastLineChecked(-1.0), 1.1085 + mRegexes(nullptr) 1.1086 + { 1.1087 + // Enable timestamps in kernel's printk 1.1088 + WriteToFile("/sys/module/printk/parameters/time", "Y"); 1.1089 + } 1.1090 + 1.1091 + NS_DECL_ISUPPORTS 1.1092 + NS_DECL_NSIOBSERVER 1.1093 +private: 1.1094 + double mLastLineChecked; 1.1095 + ScopedFreePtr<regex_t> mRegexes; 1.1096 +}; 1.1097 +NS_IMPL_ISUPPORTS(OomVictimLogger, nsIObserver); 1.1098 + 1.1099 +NS_IMETHODIMP 1.1100 +OomVictimLogger::Observe( 1.1101 + nsISupports* aSubject, 1.1102 + const char* aTopic, 1.1103 + const char16_t* aData) 1.1104 +{ 1.1105 + nsDependentCString event_type(aTopic); 1.1106 + if (!event_type.EqualsLiteral("ipc:content-shutdown")) { 1.1107 + return NS_OK; 1.1108 + } 1.1109 + 1.1110 + // OOM message finding regexes 1.1111 + const char* const regexes_raw[] = { 1.1112 + ".*select.*to kill.*", 1.1113 + ".*send sigkill to.*", 1.1114 + ".*lowmem_shrink.*, return", 1.1115 + ".*lowmem_shrink.*, ofree.*"}; 1.1116 + const size_t regex_count = ArrayLength(regexes_raw); 1.1117 + 1.1118 + // Compile our regex just in time 1.1119 + if (!mRegexes) { 1.1120 + mRegexes = static_cast<regex_t*>(malloc(sizeof(regex_t) * regex_count)); 1.1121 + for (size_t i = 0; i < regex_count; i++) { 1.1122 + int compilation_err = regcomp(&(mRegexes[i]), regexes_raw[i], REG_NOSUB); 1.1123 + if (compilation_err) { 1.1124 + OOM_LOG(ANDROID_LOG_ERROR, "Cannot compile regex \"%s\"\n", regexes_raw[i]); 1.1125 + return NS_OK; 1.1126 + } 1.1127 + } 1.1128 + } 1.1129 + 1.1130 +#ifndef KLOG_SIZE_BUFFER 1.1131 + // Upstream bionic in commit 1.1132 + // e249b059637b49a285ed9f58a2a18bfd054e5d95 1.1133 + // deprecated the old klog defs. 1.1134 + // Our current bionic does not hit this 1.1135 + // change yet so handle the future change. 1.1136 + #define KLOG_SIZE_BUFFER KLOG_WRITE 1.1137 +#else 1.1138 + // Once the change hits our bionic this ifndef 1.1139 + // can be removed. 1.1140 + #warning "Please remove KLOG_UNREAD_SIZE compatability def" 1.1141 +#endif 1.1142 + // Retreive kernel log 1.1143 + int msg_buf_size = klogctl(KLOG_SIZE_BUFFER, NULL, 0); 1.1144 + ScopedFreePtr<char> msg_buf(static_cast<char *>(malloc(msg_buf_size + 1))); 1.1145 + int read_size = klogctl(KLOG_READ_ALL, msg_buf.rwget(), msg_buf_size); 1.1146 + 1.1147 + // Turn buffer into cstring 1.1148 + read_size = read_size > msg_buf_size ? msg_buf_size : read_size; 1.1149 + msg_buf.rwget()[read_size] = '\0'; 1.1150 + 1.1151 + // Foreach line 1.1152 + char* line_end; 1.1153 + char* line_begin = msg_buf.rwget(); 1.1154 + for (; (line_end = strchr(line_begin, '\n')); line_begin = line_end + 1) { 1.1155 + // make line into cstring 1.1156 + *line_end = '\0'; 1.1157 + 1.1158 + // Note: Kernel messages look like: 1.1159 + // <5>[63648.286409] sd 35:0:0:0: Attached scsi generic sg1 type 0 1.1160 + // 5 is the loging level 1.1161 + // [*] is the time timestamp, seconds since boot 1.1162 + // last comes the logged message 1.1163 + 1.1164 + // Since the logging level can be a string we must 1.1165 + // skip it since scanf lacks wildcard matching 1.1166 + char* timestamp_begin = strchr(line_begin, '['); 1.1167 + char after_float; 1.1168 + double lineTimestamp = -1; 1.1169 + bool lineTimestampFound = false; 1.1170 + if (timestamp_begin && 1.1171 + // Note: scanf treats a ' ' as [ ]* 1.1172 + // Note: scanf treats [ %lf] as [ %lf thus we must check 1.1173 + // for the closing bracket outselves. 1.1174 + 2 == sscanf(timestamp_begin, "[ %lf%c", &lineTimestamp, &after_float) && 1.1175 + after_float == ']') { 1.1176 + if (lineTimestamp <= mLastLineChecked) { 1.1177 + continue; 1.1178 + } 1.1179 + 1.1180 + lineTimestampFound = true; 1.1181 + mLastLineChecked = lineTimestamp; 1.1182 + } 1.1183 + 1.1184 + 1.1185 + // Log interesting lines 1.1186 + for (size_t i = 0; i < regex_count; i++) { 1.1187 + int matching = !regexec(&(mRegexes[i]), line_begin, 0, NULL, 0); 1.1188 + if (matching) { 1.1189 + // Log content of kernel message. We try to skip the ], but if for 1.1190 + // some reason (most likely due to buffer overflow/wraparound), we 1.1191 + // can't find the ] then we just log the entire line. 1.1192 + char* endOfTimestamp = strchr(line_begin, ']'); 1.1193 + if (endOfTimestamp && endOfTimestamp[1] == ' ') { 1.1194 + // skip the ] and the space that follows it 1.1195 + line_begin = endOfTimestamp + 2; 1.1196 + } 1.1197 + if (!lineTimestampFound) { 1.1198 + OOM_LOG(ANDROID_LOG_WARN, "following kill message may be a duplicate"); 1.1199 + } 1.1200 + OOM_LOG(ANDROID_LOG_ERROR, "[Kill]: %s\n", line_begin); 1.1201 + break; 1.1202 + } 1.1203 + } 1.1204 + } 1.1205 + 1.1206 + return NS_OK; 1.1207 +} 1.1208 + 1.1209 +static void 1.1210 +EnsureKernelLowMemKillerParamsSet() 1.1211 +{ 1.1212 + static bool kernelLowMemKillerParamsSet; 1.1213 + if (kernelLowMemKillerParamsSet) { 1.1214 + return; 1.1215 + } 1.1216 + kernelLowMemKillerParamsSet = true; 1.1217 + 1.1218 + HAL_LOG(("Setting kernel's low-mem killer parameters.")); 1.1219 + 1.1220 + // Set /sys/module/lowmemorykiller/parameters/{adj,minfree,notify_trigger} 1.1221 + // according to our prefs. These files let us tune when the kernel kills 1.1222 + // processes when we're low on memory, and when it notifies us that we're 1.1223 + // running low on available memory. 1.1224 + // 1.1225 + // adj and minfree are both comma-separated lists of integers. If adj="A,B" 1.1226 + // and minfree="X,Y", then the kernel will kill processes with oom_adj 1.1227 + // A or higher once we have fewer than X pages of memory free, and will kill 1.1228 + // processes with oom_adj B or higher once we have fewer than Y pages of 1.1229 + // memory free. 1.1230 + // 1.1231 + // notify_trigger is a single integer. If we set notify_trigger=Z, then 1.1232 + // we'll get notified when there are fewer than Z pages of memory free. (See 1.1233 + // GonkMemoryPressureMonitoring.cpp.) 1.1234 + 1.1235 + // Build the adj and minfree strings. 1.1236 + nsAutoCString adjParams; 1.1237 + nsAutoCString minfreeParams; 1.1238 + 1.1239 + int32_t lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1; 1.1240 + int32_t lowerBoundOfNextKillUnderKB = 0; 1.1241 + int32_t countOfLowmemorykillerParametersSets = 0; 1.1242 + 1.1243 + for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) { 1.1244 + // The system doesn't function correctly if we're missing these prefs, so 1.1245 + // crash loudly. 1.1246 + 1.1247 + ProcessPriority priority = static_cast<ProcessPriority>(i); 1.1248 + 1.1249 + int32_t oomScoreAdj; 1.1250 + if (!NS_SUCCEEDED(Preferences::GetInt( 1.1251 + nsPrintfCString("hal.processPriorityManager.gonk.%s.OomScoreAdjust", 1.1252 + ProcessPriorityToString(priority)).get(), 1.1253 + &oomScoreAdj))) { 1.1254 + MOZ_CRASH(); 1.1255 + } 1.1256 + 1.1257 + int32_t killUnderKB; 1.1258 + if (!NS_SUCCEEDED(Preferences::GetInt( 1.1259 + nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB", 1.1260 + ProcessPriorityToString(priority)).get(), 1.1261 + &killUnderKB))) { 1.1262 + // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD, 1.1263 + // which has only OomScoreAdjust but lacks KillUnderMB value, will not 1.1264 + // create new LMK parameters. 1.1265 + continue; 1.1266 + } 1.1267 + 1.1268 + // The LMK in kernel silently malfunctions if we assign the parameters 1.1269 + // in non-increasing order, so we add this assertion here. See bug 887192. 1.1270 + MOZ_ASSERT(oomScoreAdj > lowerBoundOfNextOomScoreAdj); 1.1271 + MOZ_ASSERT(killUnderKB > lowerBoundOfNextKillUnderKB); 1.1272 + 1.1273 + // The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728. 1.1274 + MOZ_ASSERT(countOfLowmemorykillerParametersSets < 6); 1.1275 + 1.1276 + // adj is in oom_adj units. 1.1277 + adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj)); 1.1278 + 1.1279 + // minfree is in pages. 1.1280 + minfreeParams.AppendPrintf("%d,", killUnderKB * 1024 / PAGE_SIZE); 1.1281 + 1.1282 + lowerBoundOfNextOomScoreAdj = oomScoreAdj; 1.1283 + lowerBoundOfNextKillUnderKB = killUnderKB; 1.1284 + countOfLowmemorykillerParametersSets++; 1.1285 + } 1.1286 + 1.1287 + // Strip off trailing commas. 1.1288 + adjParams.Cut(adjParams.Length() - 1, 1); 1.1289 + minfreeParams.Cut(minfreeParams.Length() - 1, 1); 1.1290 + if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) { 1.1291 + WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get()); 1.1292 + WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", minfreeParams.get()); 1.1293 + } 1.1294 + 1.1295 + // Set the low-memory-notification threshold. 1.1296 + int32_t lowMemNotifyThresholdKB; 1.1297 + if (NS_SUCCEEDED(Preferences::GetInt( 1.1298 + "hal.processPriorityManager.gonk.notifyLowMemUnderKB", 1.1299 + &lowMemNotifyThresholdKB))) { 1.1300 + 1.1301 + // notify_trigger is in pages. 1.1302 + WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger", 1.1303 + nsPrintfCString("%d", lowMemNotifyThresholdKB * 1024 / PAGE_SIZE).get()); 1.1304 + } 1.1305 + 1.1306 + // Ensure OOM events appear in logcat 1.1307 + nsRefPtr<OomVictimLogger> oomLogger = new OomVictimLogger(); 1.1308 + nsCOMPtr<nsIObserverService> os = services::GetObserverService(); 1.1309 + if (os) { 1.1310 + os->AddObserver(oomLogger, "ipc:content-shutdown", false); 1.1311 + } 1.1312 +} 1.1313 + 1.1314 +static void 1.1315 +SetNiceForPid(int aPid, int aNice) 1.1316 +{ 1.1317 + errno = 0; 1.1318 + int origProcPriority = getpriority(PRIO_PROCESS, aPid); 1.1319 + if (errno) { 1.1320 + LOG("Unable to get nice for pid=%d; error %d. SetNiceForPid bailing.", 1.1321 + aPid, errno); 1.1322 + return; 1.1323 + } 1.1324 + 1.1325 + int rv = setpriority(PRIO_PROCESS, aPid, aNice); 1.1326 + if (rv) { 1.1327 + LOG("Unable to set nice for pid=%d; error %d. SetNiceForPid bailing.", 1.1328 + aPid, errno); 1.1329 + return; 1.1330 + } 1.1331 + 1.1332 + // On Linux, setpriority(aPid) modifies the priority only of the main 1.1333 + // thread of that process. We have to modify the priorities of all of the 1.1334 + // process's threads as well, so iterate over all the threads and increase 1.1335 + // each of their priorites by aNice - origProcPriority (and also ensure that 1.1336 + // none of the tasks has a lower priority than the main thread). 1.1337 + // 1.1338 + // This is horribly racy. 1.1339 + 1.1340 + DIR* tasksDir = opendir(nsPrintfCString("/proc/%d/task/", aPid).get()); 1.1341 + if (!tasksDir) { 1.1342 + LOG("Unable to open /proc/%d/task. SetNiceForPid bailing.", aPid); 1.1343 + return; 1.1344 + } 1.1345 + 1.1346 + // Be careful not to leak tasksDir; after this point, we must call closedir(). 1.1347 + 1.1348 + while (struct dirent* de = readdir(tasksDir)) { 1.1349 + char* endptr = nullptr; 1.1350 + long tidlong = strtol(de->d_name, &endptr, /* base */ 10); 1.1351 + if (*endptr || tidlong < 0 || tidlong > INT32_MAX || tidlong == aPid) { 1.1352 + // if dp->d_name was not an integer, was negative (?!) or too large, or 1.1353 + // was the same as aPid, we're not interested. 1.1354 + // 1.1355 + // (The |tidlong == aPid| check is very important; without it, we'll 1.1356 + // renice aPid twice, and the second renice will be relative to the 1.1357 + // priority set by the first renice.) 1.1358 + continue; 1.1359 + } 1.1360 + 1.1361 + int tid = static_cast<int>(tidlong); 1.1362 + 1.1363 + errno = 0; 1.1364 + // Get and set the task's new priority. 1.1365 + int origtaskpriority = getpriority(PRIO_PROCESS, tid); 1.1366 + if (errno) { 1.1367 + LOG("Unable to get nice for tid=%d (pid=%d); error %d. This isn't " 1.1368 + "necessarily a problem; it could be a benign race condition.", 1.1369 + tid, aPid, errno); 1.1370 + continue; 1.1371 + } 1.1372 + 1.1373 + int newtaskpriority = 1.1374 + std::max(origtaskpriority - origProcPriority + aNice, aNice); 1.1375 + rv = setpriority(PRIO_PROCESS, tid, newtaskpriority); 1.1376 + 1.1377 + if (rv) { 1.1378 + LOG("Unable to set nice for tid=%d (pid=%d); error %d. This isn't " 1.1379 + "necessarily a problem; it could be a benign race condition.", 1.1380 + tid, aPid, errno); 1.1381 + continue; 1.1382 + } 1.1383 + } 1.1384 + 1.1385 + LOG("Changed nice for pid %d from %d to %d.", 1.1386 + aPid, origProcPriority, aNice); 1.1387 + 1.1388 + closedir(tasksDir); 1.1389 +} 1.1390 + 1.1391 +void 1.1392 +SetProcessPriority(int aPid, 1.1393 + ProcessPriority aPriority, 1.1394 + ProcessCPUPriority aCPUPriority, 1.1395 + uint32_t aBackgroundLRU) 1.1396 +{ 1.1397 + HAL_LOG(("SetProcessPriority(pid=%d, priority=%d, cpuPriority=%d, LRU=%u)", 1.1398 + aPid, aPriority, aCPUPriority, aBackgroundLRU)); 1.1399 + 1.1400 + // If this is the first time SetProcessPriority was called, set the kernel's 1.1401 + // OOM parameters according to our prefs. 1.1402 + // 1.1403 + // We could/should do this on startup instead of waiting for the first 1.1404 + // SetProcessPriorityCall. But in practice, the master process needs to set 1.1405 + // its priority early in the game, so we can reasonably rely on 1.1406 + // SetProcessPriority being called early in startup. 1.1407 + EnsureKernelLowMemKillerParamsSet(); 1.1408 + 1.1409 + int32_t oomScoreAdj = 0; 1.1410 + nsresult rv = Preferences::GetInt(nsPrintfCString( 1.1411 + "hal.processPriorityManager.gonk.%s.OomScoreAdjust", 1.1412 + ProcessPriorityToString(aPriority)).get(), &oomScoreAdj); 1.1413 + 1.1414 + RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU); 1.1415 + 1.1416 + if (NS_SUCCEEDED(rv)) { 1.1417 + int clampedOomScoreAdj = clamped<int>(oomScoreAdj, OOM_SCORE_ADJ_MIN, 1.1418 + OOM_SCORE_ADJ_MAX); 1.1419 + if(clampedOomScoreAdj != oomScoreAdj) { 1.1420 + HAL_LOG(("Clamping OOM adjustment for pid %d to %d", 1.1421 + aPid, clampedOomScoreAdj)); 1.1422 + } else { 1.1423 + HAL_LOG(("Setting OOM adjustment for pid %d to %d", 1.1424 + aPid, clampedOomScoreAdj)); 1.1425 + } 1.1426 + 1.1427 + // We try the newer interface first, and fall back to the older interface 1.1428 + // on failure. 1.1429 + 1.1430 + if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(), 1.1431 + nsPrintfCString("%d", clampedOomScoreAdj).get())) 1.1432 + { 1.1433 + int oomAdj = OomAdjOfOomScoreAdj(clampedOomScoreAdj); 1.1434 + 1.1435 + WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(), 1.1436 + nsPrintfCString("%d", oomAdj).get()); 1.1437 + } 1.1438 + } else { 1.1439 + LOG("Unable to read oom_score_adj pref for priority %s; " 1.1440 + "are the prefs messed up?", 1.1441 + ProcessPriorityToString(aPriority)); 1.1442 + MOZ_ASSERT(false); 1.1443 + } 1.1444 + 1.1445 + int32_t nice = 0; 1.1446 + 1.1447 + if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { 1.1448 + rv = Preferences::GetInt( 1.1449 + nsPrintfCString("hal.processPriorityManager.gonk.%s.Nice", 1.1450 + ProcessPriorityToString(aPriority)).get(), 1.1451 + &nice); 1.1452 + } else if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { 1.1453 + rv = Preferences::GetInt("hal.processPriorityManager.gonk.LowCPUNice", 1.1454 + &nice); 1.1455 + } else { 1.1456 + LOG("Unable to read niceness pref for priority %s; " 1.1457 + "are the prefs messed up?", 1.1458 + ProcessPriorityToString(aPriority)); 1.1459 + MOZ_ASSERT(false); 1.1460 + rv = NS_ERROR_FAILURE; 1.1461 + } 1.1462 + 1.1463 + if (NS_SUCCEEDED(rv)) { 1.1464 + LOG("Setting nice for pid %d to %d", aPid, nice); 1.1465 + SetNiceForPid(aPid, nice); 1.1466 + } 1.1467 +} 1.1468 + 1.1469 +void 1.1470 +FactoryReset() 1.1471 +{ 1.1472 + nsCOMPtr<nsIRecoveryService> recoveryService = 1.1473 + do_GetService("@mozilla.org/recovery-service;1"); 1.1474 + if (!recoveryService) { 1.1475 + NS_WARNING("Could not get recovery service!"); 1.1476 + return; 1.1477 + } 1.1478 + 1.1479 + recoveryService->FactoryReset(); 1.1480 +} 1.1481 + 1.1482 +} // hal_impl 1.1483 +} // mozilla