hal/gonk/GonkHal.cpp

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:a0f7af8bb611
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 */
17
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>
30
31 #include "mozilla/DebugOnly.h"
32
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"
41
42 #include "base/message_loop.h"
43
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>
68
69 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
70 #define NsecPerMsec 1000000LL
71 #define NsecPerSec 1000000000
72
73 // The header linux/oom.h is not available in bionic libc. We
74 // redefine some of its constants here.
75
76 #ifndef OOM_DISABLE
77 #define OOM_DISABLE (-17)
78 #endif
79
80 #ifndef OOM_ADJUST_MIN
81 #define OOM_ADJUST_MIN (-16)
82 #endif
83
84 #ifndef OOM_ADJUST_MAX
85 #define OOM_ADJUST_MAX 15
86 #endif
87
88 #ifndef OOM_SCORE_ADJ_MIN
89 #define OOM_SCORE_ADJ_MIN (-1000)
90 #endif
91
92 #ifndef OOM_SCORE_ADJ_MAX
93 #define OOM_SCORE_ADJ_MAX 1000
94 #endif
95
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
102
103 using namespace mozilla;
104 using namespace mozilla::hal;
105
106 namespace mozilla {
107 namespace hal_impl {
108
109 namespace {
110
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 }
129
130 os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
131 }
132
133 NS_DECL_THREADSAFE_ISUPPORTS
134 NS_DECL_NSIRUNNABLE
135 NS_DECL_NSIOBSERVER
136
137 // Run on the main thread, not the vibrator thread.
138 void Vibrate(const nsTArray<uint32_t> &pattern);
139 void CancelVibrate();
140
141 static bool ShuttingDown() { return sShuttingDown; }
142
143 private:
144 Monitor mMonitor;
145
146 // The currently-playing pattern.
147 nsTArray<uint32_t> mPattern;
148
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;
152
153 // Set to true in our shutdown observer. When this is true, we kill the
154 // vibrator thread.
155 static bool sShuttingDown;
156 };
157
158 NS_IMPL_ISUPPORTS(VibratorRunnable, nsIRunnable, nsIObserver);
159
160 bool VibratorRunnable::sShuttingDown = false;
161
162 static StaticRefPtr<VibratorRunnable> sVibratorRunnable;
163
164 NS_IMETHODIMP
165 VibratorRunnable::Run()
166 {
167 MonitorAutoLock lock(mMonitor);
168
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.
177
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 }
194
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();
203
204 return NS_OK;
205 }
206
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 }
215
216 void
217 VibratorRunnable::CancelVibrate()
218 {
219 MonitorAutoLock lock(mMonitor);
220 mPattern.Clear();
221 mPattern.AppendElement(0);
222 mIndex = 0;
223 mMonitor.Notify();
224 }
225
226 void
227 EnsureVibratorThreadInitialized()
228 {
229 if (sVibratorRunnable) {
230 return;
231 }
232
233 sVibratorRunnable = new VibratorRunnable();
234 nsCOMPtr<nsIThread> thread;
235 NS_NewThread(getter_AddRefs(thread), sVibratorRunnable);
236 }
237
238 } // anonymous namespace
239
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 }
250
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 }
261
262 namespace {
263
264 class BatteryUpdater : public nsRunnable {
265 public:
266 NS_IMETHOD Run()
267 {
268 hal::BatteryInformation info;
269 hal_impl::GetCurrentBatteryInformation(&info);
270
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.
281
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);
289
290 hal::NotifyBatteryChange(info);
291 return NS_OK;
292 }
293 };
294
295 } // anonymous namespace
296
297 class BatteryObserver : public IUeventObserver
298 {
299 public:
300 NS_INLINE_DECL_REFCOUNTING(BatteryObserver)
301
302 BatteryObserver()
303 :mUpdater(new BatteryUpdater())
304 {
305 }
306
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 }
320
321 private:
322 nsRefPtr<BatteryUpdater> mUpdater;
323 };
324
325 // sBatteryObserver is owned by the IO thread. Only the IO thread may
326 // create or destroy it.
327 static StaticRefPtr<BatteryObserver> sBatteryObserver;
328
329 static void
330 RegisterBatteryObserverIOThread()
331 {
332 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
333 MOZ_ASSERT(!sBatteryObserver);
334
335 sBatteryObserver = new BatteryObserver();
336 RegisterUeventListener(sBatteryObserver);
337 }
338
339 void
340 EnableBatteryNotifications()
341 {
342 XRE_GetIOMessageLoop()->PostTask(
343 FROM_HERE,
344 NewRunnableFunction(RegisterBatteryObserverIOThread));
345 }
346
347 static void
348 UnregisterBatteryObserverIOThread()
349 {
350 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
351 MOZ_ASSERT(sBatteryObserver);
352
353 UnregisterUeventListener(sBatteryObserver);
354 sBatteryObserver = nullptr;
355 }
356
357 void
358 DisableBatteryNotifications()
359 {
360 XRE_GetIOMessageLoop()->PostTask(
361 FROM_HERE,
362 NewRunnableFunction(UnregisterBatteryObserverIOThread));
363 }
364
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 }
373
374 #ifdef DEBUG
375 if ((*aCharge < 0) || (*aCharge > 100)) {
376 HAL_LOG(("charge level contains unknown value: %d", *aCharge));
377 }
378 #endif
379
380 return (*aCharge >= 0) && (*aCharge <= 100);
381 }
382
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;
389
390 // Generic device support
391
392 int chargingSrc;
393 bool success =
394 ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc);
395
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
404
405 *aCharging = (chargingSrc == BATTERY_CHARGING_USB ||
406 chargingSrc == BATTERY_CHARGING_AC);
407 return true;
408 }
409
410 // Otoro device support
411
412 char chargingSrcString[16];
413
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 }
421
422 return false;
423 }
424
425 void
426 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
427 {
428 int charge;
429
430 if (GetCurrentBatteryCharge(&charge)) {
431 aBatteryInfo->level() = (double)charge / 100.0;
432 } else {
433 aBatteryInfo->level() = dom::battery::kDefaultLevel;
434 }
435
436 int charging;
437
438 if (GetCurrentBatteryCharging(&charging)) {
439 aBatteryInfo->charging() = charging;
440 } else {
441 aBatteryInfo->charging() = true;
442 }
443
444 if (!aBatteryInfo->charging() || (aBatteryInfo->level() < 1.0)) {
445 aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
446 } else {
447 aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
448 }
449 }
450
451 namespace {
452
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";
458
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 }
468
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 }
474
475 buf[std::min(numRead, n - 1)] = '\0';
476 return true;
477 }
478
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 }
487
488 if (write(fd, toWrite, strlen(toWrite)) < 0) {
489 HAL_LOG(("Unable to write to file %s.", filename));
490 return false;
491 }
492
493 return true;
494 }
495
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;
500
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;
506
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;
511
512 } // anonymous namespace
513
514 bool
515 GetScreenEnabled()
516 {
517 return sScreenEnabled;
518 }
519
520 void
521 SetScreenEnabled(bool enabled)
522 {
523 GetGonkDisplay()->SetEnabled(enabled);
524 sScreenEnabled = enabled;
525 }
526
527 double
528 GetScreenBrightness()
529 {
530 hal::LightConfiguration aConfig;
531 hal::LightType light = hal::eHalLightID_Backlight;
532
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 }
538
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 }
549
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;
554
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 }
563
564 static Monitor* sInternalLockCpuMonitor = nullptr;
565
566 static void
567 UpdateCpuSleepState()
568 {
569 sInternalLockCpuMonitor->AssertCurrentThreadOwns();
570 bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount;
571 WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
572 }
573
574 static void
575 InternalLockCpu() {
576 MonitorAutoLock monitor(*sInternalLockCpuMonitor);
577 ++sInternalLockCpuCount;
578 UpdateCpuSleepState();
579 }
580
581 static void
582 InternalUnlockCpu() {
583 MonitorAutoLock monitor(*sInternalLockCpuMonitor);
584 --sInternalLockCpuCount;
585 UpdateCpuSleepState();
586 }
587
588 bool
589 GetCpuSleepAllowed()
590 {
591 return sCpuSleepAllowed;
592 }
593
594 void
595 SetCpuSleepAllowed(bool aAllowed)
596 {
597 MonitorAutoLock monitor(*sInternalLockCpuMonitor);
598 sCpuSleepAllowed = aAllowed;
599 UpdateCpuSleepState();
600 }
601
602 static light_device_t* sLights[hal::eHalLightID_Count]; // will be initialized to nullptr
603
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 }
615
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;
624
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 }
646
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];
652
653 bool
654 SetLight(hal::LightType light, const hal::LightConfiguration& aConfig)
655 {
656 light_state_t state;
657
658 InitLights();
659
660 if (light < 0 || light >= hal::eHalLightID_Count ||
661 sLights[light] == nullptr) {
662 return false;
663 }
664
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();
671
672 sLights[light]->set_light(sLights[light], &state);
673 sStoredLightState[light] = state;
674 return true;
675 }
676
677 bool
678 GetLight(hal::LightType light, hal::LightConfiguration* aConfig)
679 {
680 light_state_t state;
681
682 #ifdef HAVEGETLIGHT
683 InitLights();
684 #endif
685
686 if (light < 0 || light >= hal::eHalLightID_Count ||
687 sLights[light] == nullptr) {
688 return false;
689 }
690
691 memset(&state, 0, sizeof(light_state_t));
692
693 #ifdef HAVEGETLIGHT
694 sLights[light]->get_light(sLights[light], &state);
695 #else
696 state = sStoredLightState[light];
697 #endif
698
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);
705
706 return true;
707 }
708
709 void
710 AdjustSystemClock(int64_t aDeltaMilliseconds)
711 {
712 int fd;
713 struct timespec now;
714
715 if (aDeltaMilliseconds == 0) {
716 return;
717 }
718
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 }
728
729 if (now.tv_nsec < 0) {
730 now.tv_nsec += NsecPerSec;
731 now.tv_sec -= 1;
732 }
733
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 }
742
743 if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) {
744 HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)));
745 }
746
747 hal::NotifySystemClockChange(aDeltaMilliseconds);
748 }
749
750 int32_t
751 GetTimezoneOffset()
752 {
753 PRExplodedTime prTime;
754 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
755
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;
759
760 // Returns the timezone offset relative to UTC in minutes.
761 return -(offset / 60);
762 }
763
764 static int32_t sKernelTimezoneOffset = 0;
765
766 static void
767 UpdateKernelTimezone(int32_t timezoneOffset)
768 {
769 if (sKernelTimezoneOffset == timezoneOffset) {
770 return;
771 }
772
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 }
786
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 }
798
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 }
810
811 nsCString
812 GetTimezone()
813 {
814 char timezone[32];
815 property_get("persist.sys.timezone", timezone, "");
816 return nsCString(timezone);
817 }
818
819 void
820 EnableSystemClockChangeNotifications()
821 {
822 }
823
824 void
825 DisableSystemClockChangeNotifications()
826 {
827 }
828
829 void
830 EnableSystemTimezoneChangeNotifications()
831 {
832 }
833
834 void
835 DisableSystemTimezoneChangeNotifications()
836 {
837 }
838
839 // Nothing to do here. Gonk widgetry always listens for screen
840 // orientation changes.
841 void
842 EnableScreenConfigurationNotifications()
843 {
844 }
845
846 void
847 DisableScreenConfigurationNotifications()
848 {
849 }
850
851 void
852 GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration)
853 {
854 *aScreenConfiguration = nsScreenGonk::GetConfiguration();
855 }
856
857 bool
858 LockScreenOrientation(const dom::ScreenOrientation& aOrientation)
859 {
860 return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation);
861 }
862
863 void
864 UnlockScreenOrientation()
865 {
866 OrientationObserver::GetInstance()->UnlockScreenOrientation();
867 }
868
869 // This thread will wait for the alarm firing by a blocking IO.
870 static pthread_t sAlarmFireWatcherThread;
871
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;
881
882 static int sNextGeneration;
883
884 };
885
886 int AlarmData::sNextGeneration = 0;
887
888 AlarmData* sAlarmData = nullptr;
889
890 class AlarmFiredEvent : public nsRunnable {
891 public:
892 AlarmFiredEvent(int aGeneration) : mGeneration(aGeneration) {}
893
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 }
906
907 private:
908 int mGeneration;
909 };
910
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 }
918
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 }
927
928 static void*
929 WaitForAlarm(void* aData)
930 {
931 pthread_cleanup_push(DestroyAlarmData, aData);
932
933 AlarmData* alarmData = static_cast<AlarmData*>(aData);
934
935 while (!alarmData->mShuttingDown) {
936 int alarmTypeFlags = 0;
937
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);
946
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 }
958
959 pthread_cleanup_pop(1);
960 return nullptr;
961 }
962
963 bool
964 EnableAlarm()
965 {
966 MOZ_ASSERT(!sAlarmData);
967
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 }
973
974 nsAutoPtr<AlarmData> alarmData(new AlarmData(alarmFd));
975
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 }
985
986 pthread_attr_t attr;
987 pthread_attr_init(&attr);
988 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
989
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;
1000 }
1001
1002 pthread_attr_destroy(&attr);
1003
1004 // The thread owns this now. We only hold a pointer.
1005 sAlarmData = alarmData.forget();
1006 return true;
1007 }
1008
1009 void
1010 DisableAlarm()
1011 {
1012 MOZ_ASSERT(sAlarmData);
1013
1014 // NB: this must happen-before the thread cancellation.
1015 sAlarmData = nullptr;
1016
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);
1021
1022 delete sInternalLockCpuMonitor;
1023 }
1024
1025 bool
1026 SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
1027 {
1028 if (!sAlarmData) {
1029 HAL_LOG(("We should have enabled the alarm."));
1030 return false;
1031 }
1032
1033 struct timespec ts;
1034 ts.tv_sec = aSeconds;
1035 ts.tv_nsec = aNanoseconds;
1036
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);
1040
1041 if (result < 0) {
1042 HAL_LOG(("Unable to set alarm: %s.", strerror(errno)));
1043 return false;
1044 }
1045
1046 return true;
1047 }
1048
1049 static int
1050 OomAdjOfOomScoreAdj(int aOomScoreAdj)
1051 {
1052 // Convert OOM adjustment from the domain of /proc/<pid>/oom_score_adj
1053 // to the domain of /proc/<pid>/oom_adj.
1054
1055 int adj;
1056
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;
1061 }
1062
1063 return adj;
1064 }
1065
1066 static void
1067 RoundOomScoreAdjUpWithBackroundLRU(int& aOomScoreAdj, uint32_t aBackgroundLRU)
1068 {
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);
1073 }
1074
1075 #define OOM_LOG(level, args...) __android_log_print(level, "OomLogger", ##args)
1076 class OomVictimLogger MOZ_FINAL
1077 : public nsIObserver
1078 {
1079 public:
1080 OomVictimLogger()
1081 : mLastLineChecked(-1.0),
1082 mRegexes(nullptr)
1083 {
1084 // Enable timestamps in kernel's printk
1085 WriteToFile("/sys/module/printk/parameters/time", "Y");
1086 }
1087
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);
1095
1096 NS_IMETHODIMP
1097 OomVictimLogger::Observe(
1098 nsISupports* aSubject,
1099 const char* aTopic,
1100 const char16_t* aData)
1101 {
1102 nsDependentCString event_type(aTopic);
1103 if (!event_type.EqualsLiteral("ipc:content-shutdown")) {
1104 return NS_OK;
1105 }
1106
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);
1114
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;
1123 }
1124 }
1125 }
1126
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);
1143
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';
1147
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';
1154
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
1160
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;
1175 }
1176
1177 lineTimestampFound = true;
1178 mLastLineChecked = lineTimestamp;
1179 }
1180
1181
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;
1193 }
1194 if (!lineTimestampFound) {
1195 OOM_LOG(ANDROID_LOG_WARN, "following kill message may be a duplicate");
1196 }
1197 OOM_LOG(ANDROID_LOG_ERROR, "[Kill]: %s\n", line_begin);
1198 break;
1199 }
1200 }
1201 }
1202
1203 return NS_OK;
1204 }
1205
1206 static void
1207 EnsureKernelLowMemKillerParamsSet()
1208 {
1209 static bool kernelLowMemKillerParamsSet;
1210 if (kernelLowMemKillerParamsSet) {
1211 return;
1212 }
1213 kernelLowMemKillerParamsSet = true;
1214
1215 HAL_LOG(("Setting kernel's low-mem killer parameters."));
1216
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.)
1231
1232 // Build the adj and minfree strings.
1233 nsAutoCString adjParams;
1234 nsAutoCString minfreeParams;
1235
1236 int32_t lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1;
1237 int32_t lowerBoundOfNextKillUnderKB = 0;
1238 int32_t countOfLowmemorykillerParametersSets = 0;
1239
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.
1243
1244 ProcessPriority priority = static_cast<ProcessPriority>(i);
1245
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();
1252 }
1253
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;
1263 }
1264
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);
1269
1270 // The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728.
1271 MOZ_ASSERT(countOfLowmemorykillerParametersSets < 6);
1272
1273 // adj is in oom_adj units.
1274 adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj));
1275
1276 // minfree is in pages.
1277 minfreeParams.AppendPrintf("%d,", killUnderKB * 1024 / PAGE_SIZE);
1278
1279 lowerBoundOfNextOomScoreAdj = oomScoreAdj;
1280 lowerBoundOfNextKillUnderKB = killUnderKB;
1281 countOfLowmemorykillerParametersSets++;
1282 }
1283
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());
1290 }
1291
1292 // Set the low-memory-notification threshold.
1293 int32_t lowMemNotifyThresholdKB;
1294 if (NS_SUCCEEDED(Preferences::GetInt(
1295 "hal.processPriorityManager.gonk.notifyLowMemUnderKB",
1296 &lowMemNotifyThresholdKB))) {
1297
1298 // notify_trigger is in pages.
1299 WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger",
1300 nsPrintfCString("%d", lowMemNotifyThresholdKB * 1024 / PAGE_SIZE).get());
1301 }
1302
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);
1308 }
1309 }
1310
1311 static void
1312 SetNiceForPid(int aPid, int aNice)
1313 {
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;
1320 }
1321
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;
1327 }
1328
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.
1336
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;
1341 }
1342
1343 // Be careful not to leak tasksDir; after this point, we must call closedir().
1344
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;
1356 }
1357
1358 int tid = static_cast<int>(tidlong);
1359
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;
1368 }
1369
1370 int newtaskpriority =
1371 std::max(origtaskpriority - origProcPriority + aNice, aNice);
1372 rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
1373
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;
1379 }
1380 }
1381
1382 LOG("Changed nice for pid %d from %d to %d.",
1383 aPid, origProcPriority, aNice);
1384
1385 closedir(tasksDir);
1386 }
1387
1388 void
1389 SetProcessPriority(int aPid,
1390 ProcessPriority aPriority,
1391 ProcessCPUPriority aCPUPriority,
1392 uint32_t aBackgroundLRU)
1393 {
1394 HAL_LOG(("SetProcessPriority(pid=%d, priority=%d, cpuPriority=%d, LRU=%u)",
1395 aPid, aPriority, aCPUPriority, aBackgroundLRU));
1396
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();
1405
1406 int32_t oomScoreAdj = 0;
1407 nsresult rv = Preferences::GetInt(nsPrintfCString(
1408 "hal.processPriorityManager.gonk.%s.OomScoreAdjust",
1409 ProcessPriorityToString(aPriority)).get(), &oomScoreAdj);
1410
1411 RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU);
1412
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));
1422 }
1423
1424 // We try the newer interface first, and fall back to the older interface
1425 // on failure.
1426
1427 if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(),
1428 nsPrintfCString("%d", clampedOomScoreAdj).get()))
1429 {
1430 int oomAdj = OomAdjOfOomScoreAdj(clampedOomScoreAdj);
1431
1432 WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(),
1433 nsPrintfCString("%d", oomAdj).get());
1434 }
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);
1440 }
1441
1442 int32_t nice = 0;
1443
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;
1458 }
1459
1460 if (NS_SUCCEEDED(rv)) {
1461 LOG("Setting nice for pid %d to %d", aPid, nice);
1462 SetNiceForPid(aPid, nice);
1463 }
1464 }
1465
1466 void
1467 FactoryReset()
1468 {
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;
1474 }
1475
1476 recoveryService->FactoryReset();
1477 }
1478
1479 } // hal_impl
1480 } // mozilla

mercurial