hal/gonk/GonkHal.cpp

changeset 0
6474c204b198
     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

mercurial