hal/gonk/GonkHal.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set sw=2 ts=8 et ft=cpp : */
     3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
     4  *
     5  * Licensed under the Apache License, Version 2.0 (the "License");
     6  * you may not use this file except in compliance with the License.
     7  * You may obtain a copy of the License at
     8  *
     9  *     http://www.apache.org/licenses/LICENSE-2.0
    10  *
    11  * Unless required by applicable law or agreed to in writing, software
    12  * distributed under the License is distributed on an "AS IS" BASIS,
    13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  * See the License for the specific language governing permissions and
    15  * limitations under the License.
    16  */
    18 #include <ctype.h>
    19 #include <errno.h>
    20 #include <fcntl.h>
    21 #include <linux/android_alarm.h>
    22 #include <math.h>
    23 #include <regex.h>
    24 #include <stdio.h>
    25 #include <sys/klog.h>
    26 #include <sys/syscall.h>
    27 #include <sys/resource.h>
    28 #include <time.h>
    29 #include <asm/page.h>
    31 #include "mozilla/DebugOnly.h"
    33 #include "android/log.h"
    34 #include "cutils/properties.h"
    35 #include "hardware/hardware.h"
    36 #include "hardware/lights.h"
    37 #include "hardware_legacy/uevent.h"
    38 #include "hardware_legacy/vibrator.h"
    39 #include "hardware_legacy/power.h"
    40 #include "libdisplay/GonkDisplay.h"
    42 #include "base/message_loop.h"
    44 #include "Hal.h"
    45 #include "HalImpl.h"
    46 #include "mozilla/ArrayUtils.h"
    47 #include "mozilla/dom/battery/Constants.h"
    48 #include "mozilla/FileUtils.h"
    49 #include "mozilla/Monitor.h"
    50 #include "mozilla/RefPtr.h"
    51 #include "mozilla/Services.h"
    52 #include "mozilla/StaticPtr.h"
    53 #include "mozilla/Preferences.h"
    54 #include "nsAlgorithm.h"
    55 #include "nsPrintfCString.h"
    56 #include "nsIObserver.h"
    57 #include "nsIObserverService.h"
    58 #include "nsIRecoveryService.h"
    59 #include "nsIRunnable.h"
    60 #include "nsScreenManagerGonk.h"
    61 #include "nsThreadUtils.h"
    62 #include "nsThreadUtils.h"
    63 #include "nsIThread.h"
    64 #include "nsXULAppAPI.h"
    65 #include "OrientationObserver.h"
    66 #include "UeventPoller.h"
    67 #include <algorithm>
    69 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
    70 #define NsecPerMsec  1000000LL
    71 #define NsecPerSec   1000000000
    73 // The header linux/oom.h is not available in bionic libc. We
    74 // redefine some of its constants here.
    76 #ifndef OOM_DISABLE
    77 #define OOM_DISABLE  (-17)
    78 #endif
    80 #ifndef OOM_ADJUST_MIN
    81 #define OOM_ADJUST_MIN  (-16)
    82 #endif
    84 #ifndef OOM_ADJUST_MAX
    85 #define OOM_ADJUST_MAX  15
    86 #endif
    88 #ifndef OOM_SCORE_ADJ_MIN
    89 #define OOM_SCORE_ADJ_MIN  (-1000)
    90 #endif
    92 #ifndef OOM_SCORE_ADJ_MAX
    93 #define OOM_SCORE_ADJ_MAX  1000
    94 #endif
    96 #ifndef BATTERY_CHARGING_ARGB
    97 #define BATTERY_CHARGING_ARGB 0x00FF0000
    98 #endif
    99 #ifndef BATTERY_FULL_ARGB
   100 #define BATTERY_FULL_ARGB 0x0000FF00
   101 #endif
   103 using namespace mozilla;
   104 using namespace mozilla::hal;
   106 namespace mozilla {
   107 namespace hal_impl {
   109 namespace {
   111 /**
   112  * This runnable runs for the lifetime of the program, once started.  It's
   113  * responsible for "playing" vibration patterns.
   114  */
   115 class VibratorRunnable
   116   : public nsIRunnable
   117   , public nsIObserver
   118 {
   119 public:
   120   VibratorRunnable()
   121     : mMonitor("VibratorRunnable")
   122     , mIndex(0)
   123   {
   124     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   125     if (!os) {
   126       NS_WARNING("Could not get observer service!");
   127       return;
   128     }
   130     os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   131   }
   133   NS_DECL_THREADSAFE_ISUPPORTS
   134   NS_DECL_NSIRUNNABLE
   135   NS_DECL_NSIOBSERVER
   137   // Run on the main thread, not the vibrator thread.
   138   void Vibrate(const nsTArray<uint32_t> &pattern);
   139   void CancelVibrate();
   141   static bool ShuttingDown() { return sShuttingDown; }
   143 private:
   144   Monitor mMonitor;
   146   // The currently-playing pattern.
   147   nsTArray<uint32_t> mPattern;
   149   // The index we're at in the currently-playing pattern.  If mIndex >=
   150   // mPattern.Length(), then we're not currently playing anything.
   151   uint32_t mIndex;
   153   // Set to true in our shutdown observer.  When this is true, we kill the
   154   // vibrator thread.
   155   static bool sShuttingDown;
   156 };
   158 NS_IMPL_ISUPPORTS(VibratorRunnable, nsIRunnable, nsIObserver);
   160 bool VibratorRunnable::sShuttingDown = false;
   162 static StaticRefPtr<VibratorRunnable> sVibratorRunnable;
   164 NS_IMETHODIMP
   165 VibratorRunnable::Run()
   166 {
   167   MonitorAutoLock lock(mMonitor);
   169   // We currently assume that mMonitor.Wait(X) waits for X milliseconds.  But in
   170   // reality, the kernel might not switch to this thread for some time after the
   171   // wait expires.  So there's potential for some inaccuracy here.
   172   //
   173   // This doesn't worry me too much.  Note that we don't even start vibrating
   174   // immediately when VibratorRunnable::Vibrate is called -- we go through a
   175   // condvar onto another thread.  Better just to be chill about small errors in
   176   // the timing here.
   178   while (!sShuttingDown) {
   179     if (mIndex < mPattern.Length()) {
   180       uint32_t duration = mPattern[mIndex];
   181       if (mIndex % 2 == 0) {
   182         vibrator_on(duration);
   183       }
   184       mIndex++;
   185       mMonitor.Wait(PR_MillisecondsToInterval(duration));
   186     }
   187     else {
   188       mMonitor.Wait();
   189     }
   190   }
   191   sVibratorRunnable = nullptr;
   192   return NS_OK;
   193 }
   195 NS_IMETHODIMP
   196 VibratorRunnable::Observe(nsISupports *subject, const char *topic,
   197                           const char16_t *data)
   198 {
   199   MOZ_ASSERT(strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
   200   MonitorAutoLock lock(mMonitor);
   201   sShuttingDown = true;
   202   mMonitor.Notify();
   204   return NS_OK;
   205 }
   207 void
   208 VibratorRunnable::Vibrate(const nsTArray<uint32_t> &pattern)
   209 {
   210   MonitorAutoLock lock(mMonitor);
   211   mPattern = pattern;
   212   mIndex = 0;
   213   mMonitor.Notify();
   214 }
   216 void
   217 VibratorRunnable::CancelVibrate()
   218 {
   219   MonitorAutoLock lock(mMonitor);
   220   mPattern.Clear();
   221   mPattern.AppendElement(0);
   222   mIndex = 0;
   223   mMonitor.Notify();
   224 }
   226 void
   227 EnsureVibratorThreadInitialized()
   228 {
   229   if (sVibratorRunnable) {
   230     return;
   231   }
   233   sVibratorRunnable = new VibratorRunnable();
   234   nsCOMPtr<nsIThread> thread;
   235   NS_NewThread(getter_AddRefs(thread), sVibratorRunnable);
   236 }
   238 } // anonymous namespace
   240 void
   241 Vibrate(const nsTArray<uint32_t> &pattern, const hal::WindowIdentifier &)
   242 {
   243   MOZ_ASSERT(NS_IsMainThread());
   244   if (VibratorRunnable::ShuttingDown()) {
   245     return;
   246   }
   247   EnsureVibratorThreadInitialized();
   248   sVibratorRunnable->Vibrate(pattern);
   249 }
   251 void
   252 CancelVibrate(const hal::WindowIdentifier &)
   253 {
   254   MOZ_ASSERT(NS_IsMainThread());
   255   if (VibratorRunnable::ShuttingDown()) {
   256     return;
   257   }
   258   EnsureVibratorThreadInitialized();
   259   sVibratorRunnable->CancelVibrate();
   260 }
   262 namespace {
   264 class BatteryUpdater : public nsRunnable {
   265 public:
   266   NS_IMETHOD Run()
   267   {
   268     hal::BatteryInformation info;
   269     hal_impl::GetCurrentBatteryInformation(&info);
   271     // Control the battery indicator (led light) here using BatteryInformation
   272     // we just retrieved.
   273     uint32_t color = 0; // Format: 0x00rrggbb.
   274     if (info.charging() && (info.level() == 1)) {
   275       // Charging and battery full.
   276       color = BATTERY_FULL_ARGB;
   277     } else if (info.charging() && (info.level() < 1)) {
   278       // Charging but not full.
   279       color = BATTERY_CHARGING_ARGB;
   280     } // else turn off battery indicator.
   282     hal::LightConfiguration aConfig(hal::eHalLightID_Battery,
   283                                     hal::eHalLightMode_User,
   284                                     hal::eHalLightFlash_None,
   285                                     0,
   286                                     0,
   287                                     color);
   288     hal_impl::SetLight(hal::eHalLightID_Battery, aConfig);
   290     hal::NotifyBatteryChange(info);
   291     return NS_OK;
   292   }
   293 };
   295 } // anonymous namespace
   297 class BatteryObserver : public IUeventObserver
   298 {
   299 public:
   300   NS_INLINE_DECL_REFCOUNTING(BatteryObserver)
   302   BatteryObserver()
   303     :mUpdater(new BatteryUpdater())
   304   {
   305   }
   307   virtual void Notify(const NetlinkEvent &aEvent)
   308   {
   309     // this will run on IO thread
   310     NetlinkEvent *event = const_cast<NetlinkEvent*>(&aEvent);
   311     const char *subsystem = event->getSubsystem();
   312     // e.g. DEVPATH=/devices/platform/sec-battery/power_supply/battery
   313     const char *devpath = event->findParam("DEVPATH");
   314     if (strcmp(subsystem, "power_supply") == 0 &&
   315         strstr(devpath, "battery")) {
   316       // aEvent will be valid only in this method.
   317       NS_DispatchToMainThread(mUpdater);
   318     }
   319   }
   321 private:
   322   nsRefPtr<BatteryUpdater> mUpdater;
   323 };
   325 // sBatteryObserver is owned by the IO thread. Only the IO thread may
   326 // create or destroy it.
   327 static StaticRefPtr<BatteryObserver> sBatteryObserver;
   329 static void
   330 RegisterBatteryObserverIOThread()
   331 {
   332   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   333   MOZ_ASSERT(!sBatteryObserver);
   335   sBatteryObserver = new BatteryObserver();
   336   RegisterUeventListener(sBatteryObserver);
   337 }
   339 void
   340 EnableBatteryNotifications()
   341 {
   342   XRE_GetIOMessageLoop()->PostTask(
   343       FROM_HERE,
   344       NewRunnableFunction(RegisterBatteryObserverIOThread));
   345 }
   347 static void
   348 UnregisterBatteryObserverIOThread()
   349 {
   350   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   351   MOZ_ASSERT(sBatteryObserver);
   353   UnregisterUeventListener(sBatteryObserver);
   354   sBatteryObserver = nullptr;
   355 }
   357 void
   358 DisableBatteryNotifications()
   359 {
   360   XRE_GetIOMessageLoop()->PostTask(
   361       FROM_HERE,
   362       NewRunnableFunction(UnregisterBatteryObserverIOThread));
   363 }
   365 static bool
   366 GetCurrentBatteryCharge(int* aCharge)
   367 {
   368   bool success = ReadSysFile("/sys/class/power_supply/battery/capacity",
   369                              aCharge);
   370   if (!success) {
   371     return false;
   372   }
   374   #ifdef DEBUG
   375   if ((*aCharge < 0) || (*aCharge > 100)) {
   376     HAL_LOG(("charge level contains unknown value: %d", *aCharge));
   377   }
   378   #endif
   380   return (*aCharge >= 0) && (*aCharge <= 100);
   381 }
   383 static bool
   384 GetCurrentBatteryCharging(int* aCharging)
   385 {
   386   static const int BATTERY_NOT_CHARGING = 0;
   387   static const int BATTERY_CHARGING_USB = 1;
   388   static const int BATTERY_CHARGING_AC  = 2;
   390   // Generic device support
   392   int chargingSrc;
   393   bool success =
   394     ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc);
   396   if (success) {
   397     #ifdef DEBUG
   398     if (chargingSrc != BATTERY_NOT_CHARGING &&
   399         chargingSrc != BATTERY_CHARGING_USB &&
   400         chargingSrc != BATTERY_CHARGING_AC) {
   401       HAL_LOG(("charging_source contained unknown value: %d", chargingSrc));
   402     }
   403     #endif
   405     *aCharging = (chargingSrc == BATTERY_CHARGING_USB ||
   406                   chargingSrc == BATTERY_CHARGING_AC);
   407     return true;
   408   }
   410   // Otoro device support
   412   char chargingSrcString[16];
   414   success = ReadSysFile("/sys/class/power_supply/battery/status",
   415                         chargingSrcString, sizeof(chargingSrcString));
   416   if (success) {
   417     *aCharging = strcmp(chargingSrcString, "Charging") == 0 ||
   418                  strcmp(chargingSrcString, "Full") == 0;
   419     return true;
   420   }
   422   return false;
   423 }
   425 void
   426 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
   427 {
   428   int charge;
   430   if (GetCurrentBatteryCharge(&charge)) {
   431     aBatteryInfo->level() = (double)charge / 100.0;
   432   } else {
   433     aBatteryInfo->level() = dom::battery::kDefaultLevel;
   434   }
   436   int charging;
   438   if (GetCurrentBatteryCharging(&charging)) {
   439     aBatteryInfo->charging() = charging;
   440   } else {
   441     aBatteryInfo->charging() = true;
   442   }
   444   if (!aBatteryInfo->charging() || (aBatteryInfo->level() < 1.0)) {
   445     aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
   446   } else {
   447     aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
   448   }
   449 }
   451 namespace {
   453 /**
   454  * RAII class to help us remember to close file descriptors.
   455  */
   456 const char *wakeLockFilename = "/sys/power/wake_lock";
   457 const char *wakeUnlockFilename = "/sys/power/wake_unlock";
   459 template<ssize_t n>
   460 bool ReadFromFile(const char *filename, char (&buf)[n])
   461 {
   462   int fd = open(filename, O_RDONLY);
   463   ScopedClose autoClose(fd);
   464   if (fd < 0) {
   465     HAL_LOG(("Unable to open file %s.", filename));
   466     return false;
   467   }
   469   ssize_t numRead = read(fd, buf, n);
   470   if (numRead < 0) {
   471     HAL_LOG(("Error reading from file %s.", filename));
   472     return false;
   473   }
   475   buf[std::min(numRead, n - 1)] = '\0';
   476   return true;
   477 }
   479 bool WriteToFile(const char *filename, const char *toWrite)
   480 {
   481   int fd = open(filename, O_WRONLY);
   482   ScopedClose autoClose(fd);
   483   if (fd < 0) {
   484     HAL_LOG(("Unable to open file %s.", filename));
   485     return false;
   486   }
   488   if (write(fd, toWrite, strlen(toWrite)) < 0) {
   489     HAL_LOG(("Unable to write to file %s.", filename));
   490     return false;
   491   }
   493   return true;
   494 }
   496 // We can write to screenEnabledFilename to enable/disable the screen, but when
   497 // we read, we always get "mem"!  So we have to keep track ourselves whether
   498 // the screen is on or not.
   499 bool sScreenEnabled = true;
   501 // We can read wakeLockFilename to find out whether the cpu wake lock
   502 // is already acquired, but reading and parsing it is a lot more work
   503 // than tracking it ourselves, and it won't be accurate anyway (kernel
   504 // internal wake locks aren't counted here.)
   505 bool sCpuSleepAllowed = true;
   507 // Some CPU wake locks may be acquired internally in HAL. We use a counter to
   508 // keep track of these needs. Note we have to hold |sInternalLockCpuMonitor|
   509 // when reading or writing this variable to ensure thread-safe.
   510 int32_t sInternalLockCpuCount = 0;
   512 } // anonymous namespace
   514 bool
   515 GetScreenEnabled()
   516 {
   517   return sScreenEnabled;
   518 }
   520 void
   521 SetScreenEnabled(bool enabled)
   522 {
   523   GetGonkDisplay()->SetEnabled(enabled);
   524   sScreenEnabled = enabled;
   525 }
   527 double
   528 GetScreenBrightness()
   529 {
   530   hal::LightConfiguration aConfig;
   531   hal::LightType light = hal::eHalLightID_Backlight;
   533   hal::GetLight(light, &aConfig);
   534   // backlight is brightness only, so using one of the RGB elements as value.
   535   int brightness = aConfig.color() & 0xFF;
   536   return brightness / 255.0;
   537 }
   539 void
   540 SetScreenBrightness(double brightness)
   541 {
   542   // Don't use De Morgan's law to push the ! into this expression; we want to
   543   // catch NaN too.
   544   if (!(0 <= brightness && brightness <= 1)) {
   545     HAL_LOG(("SetScreenBrightness: Dropping illegal brightness %f.",
   546              brightness));
   547     return;
   548   }
   550   // Convert the value in [0, 1] to an int between 0 and 255 and convert to a color
   551   // note that the high byte is FF, corresponding to the alpha channel.
   552   int val = static_cast<int>(round(brightness * 255));
   553   uint32_t color = (0xff<<24) + (val<<16) + (val<<8) + val;
   555   hal::LightConfiguration aConfig;
   556   aConfig.mode() = hal::eHalLightMode_User;
   557   aConfig.flash() = hal::eHalLightFlash_None;
   558   aConfig.flashOnMS() = aConfig.flashOffMS() = 0;
   559   aConfig.color() = color;
   560   hal::SetLight(hal::eHalLightID_Backlight, aConfig);
   561   hal::SetLight(hal::eHalLightID_Buttons, aConfig);
   562 }
   564 static Monitor* sInternalLockCpuMonitor = nullptr;
   566 static void
   567 UpdateCpuSleepState()
   568 {
   569   sInternalLockCpuMonitor->AssertCurrentThreadOwns();
   570   bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount;
   571   WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
   572 }
   574 static void
   575 InternalLockCpu() {
   576   MonitorAutoLock monitor(*sInternalLockCpuMonitor);
   577   ++sInternalLockCpuCount;
   578   UpdateCpuSleepState();
   579 }
   581 static void
   582 InternalUnlockCpu() {
   583   MonitorAutoLock monitor(*sInternalLockCpuMonitor);
   584   --sInternalLockCpuCount;
   585   UpdateCpuSleepState();
   586 }
   588 bool
   589 GetCpuSleepAllowed()
   590 {
   591   return sCpuSleepAllowed;
   592 }
   594 void
   595 SetCpuSleepAllowed(bool aAllowed)
   596 {
   597   MonitorAutoLock monitor(*sInternalLockCpuMonitor);
   598   sCpuSleepAllowed = aAllowed;
   599   UpdateCpuSleepState();
   600 }
   602 static light_device_t* sLights[hal::eHalLightID_Count];	// will be initialized to nullptr
   604 light_device_t* GetDevice(hw_module_t* module, char const* name)
   605 {
   606   int err;
   607   hw_device_t* device;
   608   err = module->methods->open(module, name, &device);
   609   if (err == 0) {
   610     return (light_device_t*)device;
   611   } else {
   612     return nullptr;
   613   }
   614 }
   616 void
   617 InitLights()
   618 {
   619   // assume that if backlight is nullptr, nothing has been set yet
   620   // if this is not true, the initialization will occur everytime a light is read or set!
   621   if (!sLights[hal::eHalLightID_Backlight]) {
   622     int err;
   623     hw_module_t* module;
   625     err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
   626     if (err == 0) {
   627       sLights[hal::eHalLightID_Backlight]
   628              = GetDevice(module, LIGHT_ID_BACKLIGHT);
   629       sLights[hal::eHalLightID_Keyboard]
   630              = GetDevice(module, LIGHT_ID_KEYBOARD);
   631       sLights[hal::eHalLightID_Buttons]
   632              = GetDevice(module, LIGHT_ID_BUTTONS);
   633       sLights[hal::eHalLightID_Battery]
   634              = GetDevice(module, LIGHT_ID_BATTERY);
   635       sLights[hal::eHalLightID_Notifications]
   636              = GetDevice(module, LIGHT_ID_NOTIFICATIONS);
   637       sLights[hal::eHalLightID_Attention]
   638              = GetDevice(module, LIGHT_ID_ATTENTION);
   639       sLights[hal::eHalLightID_Bluetooth]
   640              = GetDevice(module, LIGHT_ID_BLUETOOTH);
   641       sLights[hal::eHalLightID_Wifi]
   642              = GetDevice(module, LIGHT_ID_WIFI);
   643         }
   644     }
   645 }
   647 /**
   648  * The state last set for the lights until liblights supports
   649  * getting the light state.
   650  */
   651 static light_state_t sStoredLightState[hal::eHalLightID_Count];
   653 bool
   654 SetLight(hal::LightType light, const hal::LightConfiguration& aConfig)
   655 {
   656   light_state_t state;
   658   InitLights();
   660   if (light < 0 || light >= hal::eHalLightID_Count ||
   661       sLights[light] == nullptr) {
   662     return false;
   663   }
   665   memset(&state, 0, sizeof(light_state_t));
   666   state.color = aConfig.color();
   667   state.flashMode = aConfig.flash();
   668   state.flashOnMS = aConfig.flashOnMS();
   669   state.flashOffMS = aConfig.flashOffMS();
   670   state.brightnessMode = aConfig.mode();
   672   sLights[light]->set_light(sLights[light], &state);
   673   sStoredLightState[light] = state;
   674   return true;
   675 }
   677 bool
   678 GetLight(hal::LightType light, hal::LightConfiguration* aConfig)
   679 {
   680   light_state_t state;
   682 #ifdef HAVEGETLIGHT
   683   InitLights();
   684 #endif
   686   if (light < 0 || light >= hal::eHalLightID_Count ||
   687       sLights[light] == nullptr) {
   688     return false;
   689   }
   691   memset(&state, 0, sizeof(light_state_t));
   693 #ifdef HAVEGETLIGHT
   694   sLights[light]->get_light(sLights[light], &state);
   695 #else
   696   state = sStoredLightState[light];
   697 #endif
   699   aConfig->light() = light;
   700   aConfig->color() = state.color;
   701   aConfig->flash() = hal::FlashMode(state.flashMode);
   702   aConfig->flashOnMS() = state.flashOnMS;
   703   aConfig->flashOffMS() = state.flashOffMS;
   704   aConfig->mode() = hal::LightMode(state.brightnessMode);
   706   return true;
   707 }
   709 void
   710 AdjustSystemClock(int64_t aDeltaMilliseconds)
   711 {
   712   int fd;
   713   struct timespec now;
   715   if (aDeltaMilliseconds == 0) {
   716     return;
   717   }
   719   // Preventing context switch before setting system clock
   720   sched_yield();
   721   clock_gettime(CLOCK_REALTIME, &now);
   722   now.tv_sec += (time_t)(aDeltaMilliseconds / 1000LL);
   723   now.tv_nsec += (long)((aDeltaMilliseconds % 1000LL) * NsecPerMsec);
   724   if (now.tv_nsec >= NsecPerSec) {
   725     now.tv_sec += 1;
   726     now.tv_nsec -= NsecPerSec;
   727   }
   729   if (now.tv_nsec < 0) {
   730     now.tv_nsec += NsecPerSec;
   731     now.tv_sec -= 1;
   732   }
   734   do {
   735     fd = open("/dev/alarm", O_RDWR);
   736   } while (fd == -1 && errno == EINTR);
   737   ScopedClose autoClose(fd);
   738   if (fd < 0) {
   739     HAL_LOG(("Failed to open /dev/alarm: %s", strerror(errno)));
   740     return;
   741   }
   743   if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) {
   744     HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)));
   745   }
   747   hal::NotifySystemClockChange(aDeltaMilliseconds);
   748 }
   750 int32_t
   751 GetTimezoneOffset()
   752 {
   753   PRExplodedTime prTime;
   754   PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
   756   // Daylight saving time (DST) will be taken into account.
   757   int32_t offset = prTime.tm_params.tp_gmt_offset;
   758   offset += prTime.tm_params.tp_dst_offset;
   760   // Returns the timezone offset relative to UTC in minutes.
   761   return -(offset / 60);
   762 }
   764 static int32_t sKernelTimezoneOffset = 0;
   766 static void
   767 UpdateKernelTimezone(int32_t timezoneOffset)
   768 {
   769   if (sKernelTimezoneOffset == timezoneOffset) {
   770     return;
   771   }
   773   // Tell the kernel about the new time zone as well, so that FAT filesystems
   774   // will get local timestamps rather than UTC timestamps.
   775   //
   776   // We assume that /init.rc has a sysclktz entry so that settimeofday has
   777   // already been called once before we call it (there is a side-effect in
   778   // the kernel the very first time settimeofday is called where it does some
   779   // special processing if you only set the timezone).
   780   struct timezone tz;
   781   memset(&tz, 0, sizeof(tz));
   782   tz.tz_minuteswest = timezoneOffset;
   783   settimeofday(nullptr, &tz);
   784   sKernelTimezoneOffset = timezoneOffset;
   785 }
   787 void
   788 SetTimezone(const nsCString& aTimezoneSpec)
   789 {
   790   if (aTimezoneSpec.Equals(GetTimezone())) {
   791     // Even though the timezone hasn't changed, we still need to tell the
   792     // kernel what the current timezone is. The timezone is persisted in
   793     // a property and doesn't change across reboots, but the kernel still
   794     // needs to be updated on every boot.
   795     UpdateKernelTimezone(GetTimezoneOffset());
   796     return;
   797   }
   799   int32_t oldTimezoneOffsetMinutes = GetTimezoneOffset();
   800   property_set("persist.sys.timezone", aTimezoneSpec.get());
   801   // This function is automatically called by the other time conversion
   802   // functions that depend on the timezone. To be safe, we call it manually.
   803   tzset();
   804   int32_t newTimezoneOffsetMinutes = GetTimezoneOffset();
   805   UpdateKernelTimezone(newTimezoneOffsetMinutes);
   806   hal::NotifySystemTimezoneChange(
   807     hal::SystemTimezoneChangeInformation(
   808       oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes));
   809 }
   811 nsCString
   812 GetTimezone()
   813 {
   814   char timezone[32];
   815   property_get("persist.sys.timezone", timezone, "");
   816   return nsCString(timezone);
   817 }
   819 void
   820 EnableSystemClockChangeNotifications()
   821 {
   822 }
   824 void
   825 DisableSystemClockChangeNotifications()
   826 {
   827 }
   829 void
   830 EnableSystemTimezoneChangeNotifications()
   831 {
   832 }
   834 void
   835 DisableSystemTimezoneChangeNotifications()
   836 {
   837 }
   839 // Nothing to do here.  Gonk widgetry always listens for screen
   840 // orientation changes.
   841 void
   842 EnableScreenConfigurationNotifications()
   843 {
   844 }
   846 void
   847 DisableScreenConfigurationNotifications()
   848 {
   849 }
   851 void
   852 GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration)
   853 {
   854   *aScreenConfiguration = nsScreenGonk::GetConfiguration();
   855 }
   857 bool
   858 LockScreenOrientation(const dom::ScreenOrientation& aOrientation)
   859 {
   860   return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation);
   861 }
   863 void
   864 UnlockScreenOrientation()
   865 {
   866   OrientationObserver::GetInstance()->UnlockScreenOrientation();
   867 }
   869 // This thread will wait for the alarm firing by a blocking IO.
   870 static pthread_t sAlarmFireWatcherThread;
   872 // If |sAlarmData| is non-null, it's owned by the alarm-watcher thread.
   873 struct AlarmData {
   874 public:
   875   AlarmData(int aFd) : mFd(aFd),
   876                        mGeneration(sNextGeneration++),
   877                        mShuttingDown(false) {}
   878   ScopedClose mFd;
   879   int mGeneration;
   880   bool mShuttingDown;
   882   static int sNextGeneration;
   884 };
   886 int AlarmData::sNextGeneration = 0;
   888 AlarmData* sAlarmData = nullptr;
   890 class AlarmFiredEvent : public nsRunnable {
   891 public:
   892   AlarmFiredEvent(int aGeneration) : mGeneration(aGeneration) {}
   894   NS_IMETHOD Run() {
   895     // Guard against spurious notifications caused by an alarm firing
   896     // concurrently with it being disabled.
   897     if (sAlarmData && !sAlarmData->mShuttingDown &&
   898         mGeneration == sAlarmData->mGeneration) {
   899       hal::NotifyAlarmFired();
   900     }
   901     // The fired alarm event has been delivered to the observer (if needed);
   902     // we can now release a CPU wake lock.
   903     InternalUnlockCpu();
   904     return NS_OK;
   905   }
   907 private:
   908   int mGeneration;
   909 };
   911 // Runs on alarm-watcher thread.
   912 static void
   913 DestroyAlarmData(void* aData)
   914 {
   915   AlarmData* alarmData = static_cast<AlarmData*>(aData);
   916   delete alarmData;
   917 }
   919 // Runs on alarm-watcher thread.
   920 void ShutDownAlarm(int aSigno)
   921 {
   922   if (aSigno == SIGUSR1 && sAlarmData) {
   923     sAlarmData->mShuttingDown = true;
   924   }
   925   return;
   926 }
   928 static void*
   929 WaitForAlarm(void* aData)
   930 {
   931   pthread_cleanup_push(DestroyAlarmData, aData);
   933   AlarmData* alarmData = static_cast<AlarmData*>(aData);
   935   while (!alarmData->mShuttingDown) {
   936     int alarmTypeFlags = 0;
   938     // ALARM_WAIT apparently will block even if an alarm hasn't been
   939     // programmed, although this behavior doesn't seem to be
   940     // documented.  We rely on that here to avoid spinning the CPU
   941     // while awaiting an alarm to be programmed.
   942     do {
   943       alarmTypeFlags = ioctl(alarmData->mFd, ANDROID_ALARM_WAIT);
   944     } while (alarmTypeFlags < 0 && errno == EINTR &&
   945              !alarmData->mShuttingDown);
   947     if (!alarmData->mShuttingDown && alarmTypeFlags >= 0 &&
   948         (alarmTypeFlags & ANDROID_ALARM_RTC_WAKEUP_MASK)) {
   949       // To make sure the observer can get the alarm firing notification
   950       // *on time* (the system won't sleep during the process in any way),
   951       // we need to acquire a CPU wake lock before firing the alarm event.
   952       InternalLockCpu();
   953       nsRefPtr<AlarmFiredEvent> event =
   954         new AlarmFiredEvent(alarmData->mGeneration);
   955       NS_DispatchToMainThread(event);
   956     }
   957   }
   959   pthread_cleanup_pop(1);
   960   return nullptr;
   961 }
   963 bool
   964 EnableAlarm()
   965 {
   966   MOZ_ASSERT(!sAlarmData);
   968   int alarmFd = open("/dev/alarm", O_RDWR);
   969   if (alarmFd < 0) {
   970     HAL_LOG(("Failed to open alarm device: %s.", strerror(errno)));
   971     return false;
   972   }
   974   nsAutoPtr<AlarmData> alarmData(new AlarmData(alarmFd));
   976   struct sigaction actions;
   977   memset(&actions, 0, sizeof(actions));
   978   sigemptyset(&actions.sa_mask);
   979   actions.sa_flags = 0;
   980   actions.sa_handler = ShutDownAlarm;
   981   if (sigaction(SIGUSR1, &actions, nullptr)) {
   982     HAL_LOG(("Failed to set SIGUSR1 signal for alarm-watcher thread."));
   983     return false;
   984   }
   986   pthread_attr_t attr;
   987   pthread_attr_init(&attr);
   988   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   990   // Initialize the monitor for internally locking CPU to ensure thread-safe
   991   // before running the alarm-watcher thread.
   992   sInternalLockCpuMonitor = new Monitor("sInternalLockCpuMonitor");
   993   int status = pthread_create(&sAlarmFireWatcherThread, &attr, WaitForAlarm,
   994                               alarmData.get());
   995   if (status) {
   996     alarmData = nullptr;
   997     delete sInternalLockCpuMonitor;
   998     HAL_LOG(("Failed to create alarm-watcher thread. Status: %d.", status));
   999     return false;
  1002   pthread_attr_destroy(&attr);
  1004   // The thread owns this now.  We only hold a pointer.
  1005   sAlarmData = alarmData.forget();
  1006   return true;
  1009 void
  1010 DisableAlarm()
  1012   MOZ_ASSERT(sAlarmData);
  1014   // NB: this must happen-before the thread cancellation.
  1015   sAlarmData = nullptr;
  1017   // The cancel will interrupt the thread and destroy it, freeing the
  1018   // data pointed at by sAlarmData.
  1019   DebugOnly<int> err = pthread_kill(sAlarmFireWatcherThread, SIGUSR1);
  1020   MOZ_ASSERT(!err);
  1022   delete sInternalLockCpuMonitor;
  1025 bool
  1026 SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
  1028   if (!sAlarmData) {
  1029     HAL_LOG(("We should have enabled the alarm."));
  1030     return false;
  1033   struct timespec ts;
  1034   ts.tv_sec = aSeconds;
  1035   ts.tv_nsec = aNanoseconds;
  1037   // Currently we only support RTC wakeup alarm type.
  1038   const int result = ioctl(sAlarmData->mFd,
  1039                            ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP), &ts);
  1041   if (result < 0) {
  1042     HAL_LOG(("Unable to set alarm: %s.", strerror(errno)));
  1043     return false;
  1046   return true;
  1049 static int
  1050 OomAdjOfOomScoreAdj(int aOomScoreAdj)
  1052   // Convert OOM adjustment from the domain of /proc/<pid>/oom_score_adj
  1053   // to the domain of /proc/<pid>/oom_adj.
  1055   int adj;
  1057   if (aOomScoreAdj < 0) {
  1058     adj = (OOM_DISABLE * aOomScoreAdj) / OOM_SCORE_ADJ_MIN;
  1059   } else {
  1060     adj = (OOM_ADJUST_MAX * aOomScoreAdj) / OOM_SCORE_ADJ_MAX;
  1063   return adj;
  1066 static void
  1067 RoundOomScoreAdjUpWithBackroundLRU(int& aOomScoreAdj, uint32_t aBackgroundLRU)
  1069   // We want to add minimum value to round OomScoreAdj up according to
  1070   // the steps by aBackgroundLRU.
  1071   aOomScoreAdj +=
  1072     ceil(((float)OOM_SCORE_ADJ_MAX / OOM_ADJUST_MAX) * aBackgroundLRU);
  1075 #define OOM_LOG(level, args...) __android_log_print(level, "OomLogger", ##args)
  1076 class OomVictimLogger MOZ_FINAL
  1077   : public nsIObserver
  1079 public:
  1080   OomVictimLogger()
  1081     : mLastLineChecked(-1.0),
  1082       mRegexes(nullptr)
  1084     // Enable timestamps in kernel's printk
  1085     WriteToFile("/sys/module/printk/parameters/time", "Y");
  1088   NS_DECL_ISUPPORTS
  1089   NS_DECL_NSIOBSERVER
  1090 private:
  1091   double mLastLineChecked;
  1092   ScopedFreePtr<regex_t> mRegexes;
  1093 };
  1094 NS_IMPL_ISUPPORTS(OomVictimLogger, nsIObserver);
  1096 NS_IMETHODIMP
  1097 OomVictimLogger::Observe(
  1098   nsISupports* aSubject,
  1099   const char* aTopic,
  1100   const char16_t* aData)
  1102   nsDependentCString event_type(aTopic);
  1103   if (!event_type.EqualsLiteral("ipc:content-shutdown")) {
  1104     return NS_OK;
  1107   // OOM message finding regexes
  1108   const char* const regexes_raw[] = {
  1109     ".*select.*to kill.*",
  1110     ".*send sigkill to.*",
  1111     ".*lowmem_shrink.*, return",
  1112     ".*lowmem_shrink.*, ofree.*"};
  1113   const size_t regex_count = ArrayLength(regexes_raw);
  1115   // Compile our regex just in time
  1116   if (!mRegexes) {
  1117     mRegexes = static_cast<regex_t*>(malloc(sizeof(regex_t) * regex_count));
  1118     for (size_t i = 0; i < regex_count; i++) {
  1119       int compilation_err = regcomp(&(mRegexes[i]), regexes_raw[i], REG_NOSUB);
  1120       if (compilation_err) {
  1121         OOM_LOG(ANDROID_LOG_ERROR, "Cannot compile regex \"%s\"\n", regexes_raw[i]);
  1122         return NS_OK;
  1127 #ifndef KLOG_SIZE_BUFFER
  1128   // Upstream bionic in commit
  1129   // e249b059637b49a285ed9f58a2a18bfd054e5d95
  1130   // deprecated the old klog defs.
  1131   // Our current bionic does not hit this
  1132   // change yet so handle the future change.
  1133   #define KLOG_SIZE_BUFFER KLOG_WRITE
  1134 #else
  1135   // Once the change hits our bionic this ifndef
  1136   // can be removed.
  1137   #warning "Please remove KLOG_UNREAD_SIZE compatability def"
  1138 #endif
  1139   // Retreive kernel log
  1140   int msg_buf_size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
  1141   ScopedFreePtr<char> msg_buf(static_cast<char *>(malloc(msg_buf_size + 1)));
  1142   int read_size = klogctl(KLOG_READ_ALL, msg_buf.rwget(), msg_buf_size);
  1144   // Turn buffer into cstring
  1145   read_size = read_size > msg_buf_size ? msg_buf_size : read_size;
  1146   msg_buf.rwget()[read_size] = '\0';
  1148   // Foreach line
  1149   char* line_end;
  1150   char* line_begin = msg_buf.rwget();
  1151   for (; (line_end = strchr(line_begin, '\n')); line_begin = line_end + 1) {
  1152     // make line into cstring
  1153     *line_end = '\0';
  1155     // Note: Kernel messages look like:
  1156     // <5>[63648.286409] sd 35:0:0:0: Attached scsi generic sg1 type 0
  1157     // 5 is the loging level
  1158     // [*] is the time timestamp, seconds since boot
  1159     // last comes the logged message
  1161     // Since the logging level can be a string we must
  1162     // skip it since scanf lacks wildcard matching
  1163     char*  timestamp_begin = strchr(line_begin, '[');
  1164     char   after_float;
  1165     double lineTimestamp = -1;
  1166     bool   lineTimestampFound = false;
  1167     if (timestamp_begin &&
  1168          // Note: scanf treats a ' ' as [ ]*
  1169          // Note: scanf treats [ %lf] as [ %lf thus we must check
  1170          // for the closing bracket outselves.
  1171          2 == sscanf(timestamp_begin, "[ %lf%c", &lineTimestamp, &after_float) &&
  1172          after_float == ']') {
  1173       if (lineTimestamp <= mLastLineChecked) {
  1174         continue;
  1177       lineTimestampFound = true;
  1178       mLastLineChecked = lineTimestamp;
  1182     // Log interesting lines
  1183     for (size_t i = 0; i < regex_count; i++) {
  1184       int matching = !regexec(&(mRegexes[i]), line_begin, 0, NULL, 0);
  1185       if (matching) {
  1186         // Log content of kernel message. We try to skip the ], but if for
  1187         // some reason (most likely due to buffer overflow/wraparound), we
  1188         // can't find the ] then we just log the entire line.
  1189         char* endOfTimestamp = strchr(line_begin, ']');
  1190         if (endOfTimestamp && endOfTimestamp[1] == ' ') {
  1191           // skip the ] and the space that follows it
  1192           line_begin = endOfTimestamp + 2;
  1194         if (!lineTimestampFound) {
  1195           OOM_LOG(ANDROID_LOG_WARN, "following kill message may be a duplicate");
  1197         OOM_LOG(ANDROID_LOG_ERROR, "[Kill]: %s\n", line_begin);
  1198         break;
  1203   return NS_OK;
  1206 static void
  1207 EnsureKernelLowMemKillerParamsSet()
  1209   static bool kernelLowMemKillerParamsSet;
  1210   if (kernelLowMemKillerParamsSet) {
  1211     return;
  1213   kernelLowMemKillerParamsSet = true;
  1215   HAL_LOG(("Setting kernel's low-mem killer parameters."));
  1217   // Set /sys/module/lowmemorykiller/parameters/{adj,minfree,notify_trigger}
  1218   // according to our prefs.  These files let us tune when the kernel kills
  1219   // processes when we're low on memory, and when it notifies us that we're
  1220   // running low on available memory.
  1221   //
  1222   // adj and minfree are both comma-separated lists of integers.  If adj="A,B"
  1223   // and minfree="X,Y", then the kernel will kill processes with oom_adj
  1224   // A or higher once we have fewer than X pages of memory free, and will kill
  1225   // processes with oom_adj B or higher once we have fewer than Y pages of
  1226   // memory free.
  1227   //
  1228   // notify_trigger is a single integer.   If we set notify_trigger=Z, then
  1229   // we'll get notified when there are fewer than Z pages of memory free.  (See
  1230   // GonkMemoryPressureMonitoring.cpp.)
  1232   // Build the adj and minfree strings.
  1233   nsAutoCString adjParams;
  1234   nsAutoCString minfreeParams;
  1236   int32_t lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1;
  1237   int32_t lowerBoundOfNextKillUnderKB = 0;
  1238   int32_t countOfLowmemorykillerParametersSets = 0;
  1240   for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) {
  1241     // The system doesn't function correctly if we're missing these prefs, so
  1242     // crash loudly.
  1244     ProcessPriority priority = static_cast<ProcessPriority>(i);
  1246     int32_t oomScoreAdj;
  1247     if (!NS_SUCCEEDED(Preferences::GetInt(
  1248           nsPrintfCString("hal.processPriorityManager.gonk.%s.OomScoreAdjust",
  1249                           ProcessPriorityToString(priority)).get(),
  1250           &oomScoreAdj))) {
  1251       MOZ_CRASH();
  1254     int32_t killUnderKB;
  1255     if (!NS_SUCCEEDED(Preferences::GetInt(
  1256           nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
  1257                           ProcessPriorityToString(priority)).get(),
  1258           &killUnderKB))) {
  1259       // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
  1260       // which has only OomScoreAdjust but lacks KillUnderMB value, will not
  1261       // create new LMK parameters.
  1262       continue;
  1265     // The LMK in kernel silently malfunctions if we assign the parameters
  1266     // in non-increasing order, so we add this assertion here. See bug 887192.
  1267     MOZ_ASSERT(oomScoreAdj > lowerBoundOfNextOomScoreAdj);
  1268     MOZ_ASSERT(killUnderKB > lowerBoundOfNextKillUnderKB);
  1270     // The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728.
  1271     MOZ_ASSERT(countOfLowmemorykillerParametersSets < 6);
  1273     // adj is in oom_adj units.
  1274     adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj));
  1276     // minfree is in pages.
  1277     minfreeParams.AppendPrintf("%d,", killUnderKB * 1024 / PAGE_SIZE);
  1279     lowerBoundOfNextOomScoreAdj = oomScoreAdj;
  1280     lowerBoundOfNextKillUnderKB = killUnderKB;
  1281     countOfLowmemorykillerParametersSets++;
  1284   // Strip off trailing commas.
  1285   adjParams.Cut(adjParams.Length() - 1, 1);
  1286   minfreeParams.Cut(minfreeParams.Length() - 1, 1);
  1287   if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) {
  1288     WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get());
  1289     WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", minfreeParams.get());
  1292   // Set the low-memory-notification threshold.
  1293   int32_t lowMemNotifyThresholdKB;
  1294   if (NS_SUCCEEDED(Preferences::GetInt(
  1295         "hal.processPriorityManager.gonk.notifyLowMemUnderKB",
  1296         &lowMemNotifyThresholdKB))) {
  1298     // notify_trigger is in pages.
  1299     WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger",
  1300       nsPrintfCString("%d", lowMemNotifyThresholdKB * 1024 / PAGE_SIZE).get());
  1303   // Ensure OOM events appear in logcat
  1304   nsRefPtr<OomVictimLogger> oomLogger = new OomVictimLogger();
  1305   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1306   if (os) {
  1307     os->AddObserver(oomLogger, "ipc:content-shutdown", false);
  1311 static void
  1312 SetNiceForPid(int aPid, int aNice)
  1314   errno = 0;
  1315   int origProcPriority = getpriority(PRIO_PROCESS, aPid);
  1316   if (errno) {
  1317     LOG("Unable to get nice for pid=%d; error %d.  SetNiceForPid bailing.",
  1318         aPid, errno);
  1319     return;
  1322   int rv = setpriority(PRIO_PROCESS, aPid, aNice);
  1323   if (rv) {
  1324     LOG("Unable to set nice for pid=%d; error %d.  SetNiceForPid bailing.",
  1325         aPid, errno);
  1326     return;
  1329   // On Linux, setpriority(aPid) modifies the priority only of the main
  1330   // thread of that process.  We have to modify the priorities of all of the
  1331   // process's threads as well, so iterate over all the threads and increase
  1332   // each of their priorites by aNice - origProcPriority (and also ensure that
  1333   // none of the tasks has a lower priority than the main thread).
  1334   //
  1335   // This is horribly racy.
  1337   DIR* tasksDir = opendir(nsPrintfCString("/proc/%d/task/", aPid).get());
  1338   if (!tasksDir) {
  1339     LOG("Unable to open /proc/%d/task.  SetNiceForPid bailing.", aPid);
  1340     return;
  1343   // Be careful not to leak tasksDir; after this point, we must call closedir().
  1345   while (struct dirent* de = readdir(tasksDir)) {
  1346     char* endptr = nullptr;
  1347     long tidlong = strtol(de->d_name, &endptr, /* base */ 10);
  1348     if (*endptr || tidlong < 0 || tidlong > INT32_MAX || tidlong == aPid) {
  1349       // if dp->d_name was not an integer, was negative (?!) or too large, or
  1350       // was the same as aPid, we're not interested.
  1351       //
  1352       // (The |tidlong == aPid| check is very important; without it, we'll
  1353       // renice aPid twice, and the second renice will be relative to the
  1354       // priority set by the first renice.)
  1355       continue;
  1358     int tid = static_cast<int>(tidlong);
  1360     errno = 0;
  1361     // Get and set the task's new priority.
  1362     int origtaskpriority = getpriority(PRIO_PROCESS, tid);
  1363     if (errno) {
  1364       LOG("Unable to get nice for tid=%d (pid=%d); error %d.  This isn't "
  1365           "necessarily a problem; it could be a benign race condition.",
  1366           tid, aPid, errno);
  1367       continue;
  1370     int newtaskpriority =
  1371       std::max(origtaskpriority - origProcPriority + aNice, aNice);
  1372     rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
  1374     if (rv) {
  1375       LOG("Unable to set nice for tid=%d (pid=%d); error %d.  This isn't "
  1376           "necessarily a problem; it could be a benign race condition.",
  1377           tid, aPid, errno);
  1378       continue;
  1382   LOG("Changed nice for pid %d from %d to %d.",
  1383       aPid, origProcPriority, aNice);
  1385   closedir(tasksDir);
  1388 void
  1389 SetProcessPriority(int aPid,
  1390                    ProcessPriority aPriority,
  1391                    ProcessCPUPriority aCPUPriority,
  1392                    uint32_t aBackgroundLRU)
  1394   HAL_LOG(("SetProcessPriority(pid=%d, priority=%d, cpuPriority=%d, LRU=%u)",
  1395            aPid, aPriority, aCPUPriority, aBackgroundLRU));
  1397   // If this is the first time SetProcessPriority was called, set the kernel's
  1398   // OOM parameters according to our prefs.
  1399   //
  1400   // We could/should do this on startup instead of waiting for the first
  1401   // SetProcessPriorityCall.  But in practice, the master process needs to set
  1402   // its priority early in the game, so we can reasonably rely on
  1403   // SetProcessPriority being called early in startup.
  1404   EnsureKernelLowMemKillerParamsSet();
  1406   int32_t oomScoreAdj = 0;
  1407   nsresult rv = Preferences::GetInt(nsPrintfCString(
  1408     "hal.processPriorityManager.gonk.%s.OomScoreAdjust",
  1409     ProcessPriorityToString(aPriority)).get(), &oomScoreAdj);
  1411   RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU);
  1413   if (NS_SUCCEEDED(rv)) {
  1414     int clampedOomScoreAdj = clamped<int>(oomScoreAdj, OOM_SCORE_ADJ_MIN,
  1415                                                        OOM_SCORE_ADJ_MAX);
  1416     if(clampedOomScoreAdj != oomScoreAdj) {
  1417       HAL_LOG(("Clamping OOM adjustment for pid %d to %d",
  1418                aPid, clampedOomScoreAdj));
  1419     } else {
  1420       HAL_LOG(("Setting OOM adjustment for pid %d to %d",
  1421                aPid, clampedOomScoreAdj));
  1424     // We try the newer interface first, and fall back to the older interface
  1425     // on failure.
  1427     if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(),
  1428                      nsPrintfCString("%d", clampedOomScoreAdj).get()))
  1430       int oomAdj = OomAdjOfOomScoreAdj(clampedOomScoreAdj);
  1432       WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(),
  1433                   nsPrintfCString("%d", oomAdj).get());
  1435   } else {
  1436     LOG("Unable to read oom_score_adj pref for priority %s; "
  1437         "are the prefs messed up?",
  1438         ProcessPriorityToString(aPriority));
  1439     MOZ_ASSERT(false);
  1442   int32_t nice = 0;
  1444   if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
  1445     rv = Preferences::GetInt(
  1446       nsPrintfCString("hal.processPriorityManager.gonk.%s.Nice",
  1447                       ProcessPriorityToString(aPriority)).get(),
  1448       &nice);
  1449   } else if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
  1450     rv = Preferences::GetInt("hal.processPriorityManager.gonk.LowCPUNice",
  1451                              &nice);
  1452   } else {
  1453     LOG("Unable to read niceness pref for priority %s; "
  1454         "are the prefs messed up?",
  1455         ProcessPriorityToString(aPriority));
  1456     MOZ_ASSERT(false);
  1457     rv = NS_ERROR_FAILURE;
  1460   if (NS_SUCCEEDED(rv)) {
  1461     LOG("Setting nice for pid %d to %d", aPid, nice);
  1462     SetNiceForPid(aPid, nice);
  1466 void
  1467 FactoryReset()
  1469   nsCOMPtr<nsIRecoveryService> recoveryService =
  1470     do_GetService("@mozilla.org/recovery-service;1");
  1471   if (!recoveryService) {
  1472     NS_WARNING("Could not get recovery service!");
  1473     return;
  1476   recoveryService->FactoryReset();
  1479 } // hal_impl
  1480 } // mozilla

mercurial