Merge "init: Set perms for interactive cpufreq governor boostpulse" into jb-dev
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index f672336..323a09d 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <ctype.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -34,12 +35,51 @@
     exit(1);
 }
 
+struct fs_config_entry {
+    char* name;
+    int uid, gid, mode;
+};
+
+static struct fs_config_entry* canned_config = NULL;
+
+/* Each line in the canned file should be a path plus three ints (uid,
+ * gid, mode). */
+#ifdef PATH_MAX
+#define CANNED_LINE_LENGTH  (PATH_MAX+100)
+#else
+#define CANNED_LINE_LENGTH  (1024)
+#endif
+
 static int verbose = 0;
 static int total_size = 0;
 
 static void fix_stat(const char *path, struct stat *s)
 {
-    fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
+    if (canned_config) {
+        // Use the list of file uid/gid/modes loaded from the file
+        // given with -f.
+
+        struct fs_config_entry* empty_path_config = NULL;
+        struct fs_config_entry* p;
+        for (p = canned_config; p->name; ++p) {
+            if (!p->name[0]) {
+                empty_path_config = p;
+            }
+            if (strcmp(p->name, path) == 0) {
+                s->st_uid = p->uid;
+                s->st_gid = p->gid;
+                s->st_mode = p->mode | (s->st_mode & ~07777);
+                return;
+            }
+        }
+        s->st_uid = empty_path_config->uid;
+        s->st_gid = empty_path_config->gid;
+        s->st_mode = empty_path_config->mode | (s->st_mode & ~07777);
+    } else {
+        // Use the compiled-in fs_config() function.
+
+        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
+    }
 }
 
 static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
@@ -79,7 +119,7 @@
 
     total_size += 6 + 8*13 + olen + 1;
 
-    if(strlen(out) != olen) die("ACK!");
+    if(strlen(out) != (unsigned int)olen) die("ACK!");
 
     while(total_size & 3) {
         total_size++;
@@ -235,11 +275,61 @@
     _archive_dir(in, out, strlen(in), strlen(out));
 }
 
+static void read_canned_config(char* filename)
+{
+    int allocated = 8;
+    int used = 0;
+
+    canned_config =
+        (struct fs_config_entry*)malloc(allocated * sizeof(struct fs_config_entry));
+
+    char line[CANNED_LINE_LENGTH];
+    FILE* f = fopen(filename, "r");
+    if (f == NULL) die("failed to open canned file");
+
+    while (fgets(line, CANNED_LINE_LENGTH, f) != NULL) {
+        if (!line[0]) break;
+        if (used >= allocated) {
+            allocated *= 2;
+            canned_config = (struct fs_config_entry*)realloc(
+                canned_config, allocated * sizeof(struct fs_config_entry));
+        }
+
+        struct fs_config_entry* cc = canned_config + used;
+
+        if (isspace(line[0])) {
+            cc->name = strdup("");
+            cc->uid = atoi(strtok(line, " \n"));
+        } else {
+            cc->name = strdup(strtok(line, " \n"));
+            cc->uid = atoi(strtok(NULL, " \n"));
+        }
+        cc->gid = atoi(strtok(NULL, " \n"));
+        cc->mode = strtol(strtok(NULL, " \n"), NULL, 8);
+        ++used;
+    }
+    if (used >= allocated) {
+        ++allocated;
+        canned_config = (struct fs_config_entry*)realloc(
+            canned_config, allocated * sizeof(struct fs_config_entry));
+    }
+    canned_config[used].name = NULL;
+
+    fclose(f);
+}
+
+
 int main(int argc, char *argv[])
 {
     argc--;
     argv++;
 
+    if (argc > 1 && strcmp(argv[0], "-f") == 0) {
+        read_canned_config(argv[1]);
+        argc -= 2;
+        argv += 2;
+    }
+
     if(argc == 0) die("no directories to process?!");
 
     while(argc-- > 0){
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 994eeae..46b0828 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -255,6 +255,7 @@
 #else
     fd = fileno(tmpfile());
 #endif
+    /* reset ext4fs info so we can be called multiple times */
     reset_ext4fs_info();
     info.len = image->partition_size;
     make_ext4fs_internal(fd, NULL, NULL, NULL, 0, 1, 0, 0, 0, NULL);
@@ -266,7 +267,7 @@
     close(fd);
 }
 
-int fb_format(Action *a, usb_handle *usb)
+int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
 {
     const char *partition = a->cmd;
     char response[FB_RESPONSE_SZ+1];
@@ -281,6 +282,13 @@
     snprintf(cmd, sizeof(cmd), "getvar:partition-type:%s", partition);
     status = fb_command_response(usb, cmd, response);
     if (status) {
+        if (skip_if_not_supported) {
+            fprintf(stderr,
+                    "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr,
+                    "Can't determine partition type.\n");
+            return 0;
+        }
         fprintf(stderr,"FAILED (%s)\n", fb_get_error());
         return status;
     }
@@ -292,6 +300,13 @@
         }
     }
     if (!generator) {
+        if (skip_if_not_supported) {
+            fprintf(stderr,
+                    "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr,
+                    "File system type %s not supported.\n", response);
+            return 0;
+        }
         fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
                 response);
         return -1;
@@ -301,6 +316,12 @@
     snprintf(cmd, sizeof(cmd), "getvar:partition-size:%s", partition);
     status = fb_command_response(usb, cmd, response);
     if (status) {
+        if (skip_if_not_supported) {
+            fprintf(stderr,
+                    "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr, "Unable to get partition size\n.");
+            return 0;
+        }
         fprintf(stderr,"FAILED (%s)\n", fb_get_error());
         return status;
     }
@@ -329,11 +350,12 @@
     return status;
 }
 
-void fb_queue_format(const char *partition)
+void fb_queue_format(const char *partition, int skip_if_not_supported)
 {
     Action *a;
 
     a = queue_action(OP_FORMAT, partition);
+    a->data = (void*)skip_if_not_supported;
     a->msg = mkmsg("formatting '%s' partition", partition);
 }
 
@@ -545,7 +567,7 @@
         } else if (a->op == OP_NOTICE) {
             fprintf(stderr,"%s\n",(char*)a->data);
         } else if (a->op == OP_FORMAT) {
-            status = fb_format(a, usb);
+            status = fb_format(a, usb, (int)a->data);
             status = a->func(a, status, status ? fb_get_error() : "");
             if (status) break;
         } else {
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index af61f88..848cea3 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -640,7 +640,7 @@
             skip(2);
         } else if(!strcmp(*argv, "format")) {
             require(2);
-            fb_queue_format(argv[1]);
+            fb_queue_format(argv[1], 0);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -727,7 +727,9 @@
 
     if (wants_wipe) {
         fb_queue_erase("userdata");
+        fb_queue_format("userdata", 1);
         fb_queue_erase("cache");
+        fb_queue_format("cache", 1);
     }
     if (wants_reboot) {
         fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 7d56ecb..1d3e2b8 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,7 +43,7 @@
 /* engine.c - high level command queue engine */
 void fb_queue_flash(const char *ptn, void *data, unsigned sz);;
 void fb_queue_erase(const char *ptn);
-void fb_queue_format(const char *ptn);
+void fb_queue_format(const char *ptn, int skip_if_not_supported);
 void fb_queue_require(const char *prod, const char *var, int invert,
         unsigned nvalues, const char **value);
 void fb_queue_display(const char *var, const char *prettyname);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 68928eb..6521cbe 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -138,7 +138,7 @@
 
 #define android_id_count \
     (sizeof(android_ids) / sizeof(android_ids[0]))
-    
+
 struct fs_path_config {
     unsigned mode;
     unsigned uid;
@@ -234,7 +234,7 @@
 {
     struct fs_path_config *pc;
     int plen;
-    
+
     pc = dir ? android_dirs : android_files;
     plen = strlen(path);
     for(; pc->prefix; pc++){
@@ -254,9 +254,9 @@
     *uid = pc->uid;
     *gid = pc->gid;
     *mode = (*mode & (~07777)) | pc->mode;
-    
+
 #if 0
-    fprintf(stderr,"< '%s' '%s' %d %d %o >\n", 
+    fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
             path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);
 #endif
 }
diff --git a/include/system/camera.h b/include/system/camera.h
index b8389b1..e4cacc5 100644
--- a/include/system/camera.h
+++ b/include/system/camera.h
@@ -137,7 +137,8 @@
      * KEY_FOCUS_AREAS and KEY_METERING_AREAS have no effect.
      *
      * arg1 is the face detection type. It can be CAMERA_FACE_DETECTION_HW or
-     * CAMERA_FACE_DETECTION_SW.
+     * CAMERA_FACE_DETECTION_SW. If the type of face detection requested is not
+     * supported, the HAL must return BAD_VALUE.
      */
     CAMERA_CMD_START_FACE_DETECTION = 6,
 
diff --git a/include/system/window.h b/include/system/window.h
index 1a036df..8e00bcd 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -248,7 +248,7 @@
     NATIVE_WINDOW_API_CONNECT               = 13,   /* private */
     NATIVE_WINDOW_API_DISCONNECT            = 14,   /* private */
     NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
-    NATIVE_WINDOW_SET_ACTIVE_RECT           = 16,   /* private */
+    NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -298,6 +298,11 @@
      * of the buffer matches the window size (cropping in the process)
      */
     NATIVE_WINDOW_SCALING_MODE_SCALE_CROP       = 2,
+    /* the window is clipped to the size of the buffer's crop rectangle; pixels
+     * outside the crop rectangle are treated as if they are completely
+     * transparent.
+     */
+    NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP    = 3,
 };
 
 /* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
@@ -440,7 +445,7 @@
      *     NATIVE_WINDOW_API_CONNECT            (private)
      *     NATIVE_WINDOW_API_DISCONNECT         (private)
      *     NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS (private)
-     *     NATIVE_WINDOW_SET_ACTIVE_RECT        (private)
+     *     NATIVE_WINDOW_SET_POST_TRANSFORM_CROP (private)
      *
      */
 
@@ -504,14 +509,16 @@
 /*
  * native_window_set_crop(..., crop)
  * Sets which region of the next queued buffers needs to be considered.
- * A buffer's crop region is scaled to match the surface's size.
+ * Depending on the scaling mode, a buffer's crop region is scaled and/or
+ * cropped to match the surface's size.  This function sets the crop in
+ * pre-transformed buffer pixel coordinates.
  *
  * The specified crop region applies to all buffers queued after it is called.
  *
- * if 'crop' is NULL, subsequently queued buffers won't be cropped.
+ * If 'crop' is NULL, subsequently queued buffers won't be cropped.
  *
- * An error is returned if for instance the crop region is invalid,
- * out of the buffer's bound or if the window is invalid.
+ * An error is returned if for instance the crop region is invalid, out of the
+ * buffer's bound or if the window is invalid.
  */
 static inline int native_window_set_crop(
         struct ANativeWindow* window,
@@ -521,23 +528,38 @@
 }
 
 /*
+ * native_window_set_post_transform_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
+ * Depending on the scaling mode, a buffer's crop region is scaled and/or
+ * cropped to match the surface's size.  This function sets the crop in
+ * post-transformed pixel coordinates.
+ *
+ * The specified crop region applies to all buffers queued after it is called.
+ *
+ * If 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid, out of the
+ * buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_post_transform_crop(
+        struct ANativeWindow* window,
+        android_native_rect_t const * crop)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
+}
+
+/*
  * native_window_set_active_rect(..., active_rect)
- * Sets the region of future queued buffers that are 'active'.  Pixels outside
- * this 'active' region are considered to be completely transparent regardless
- * of the pixel values in the buffer.  The active_rect argument specifies the
- * active rectangle in buffer pixel coordinates.
  *
- * The specified active rectangle applies to all buffers queued after it is
- * called.
- *
- * An error is returned if for instance the crop region is invalid,
- * out of the buffer's bound or if the window is invalid.
+ * This function is deprectated and will be removed soon.  For now it simply
+ * sets the post-transform crop for compatibility while multi-project commits
+ * get checked.
  */
 static inline int native_window_set_active_rect(
         struct ANativeWindow* window,
         android_native_rect_t const * active_rect)
 {
-    return window->perform(window, NATIVE_WINDOW_SET_ACTIVE_RECT, active_rect);
+    return native_window_set_post_transform_crop(window, active_rect);
 }
 
 /*
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 20771c0..e03ce00 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -16,24 +16,31 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "SchedPolicy"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <cutils/sched_policy.h>
+#include <cutils/log.h>
 
-#define LOG_TAG "SchedPolicy"
-#include "cutils/log.h"
+/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
+ * Call this any place a SchedPolicy is used as an input parameter.
+ * Returns the possibly re-mapped policy.
+ */
+static inline SchedPolicy _policy(SchedPolicy p)
+{
+   return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
+}
 
-#ifdef HAVE_SCHED_H
-#ifdef HAVE_PTHREADS
+#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
 
 #include <sched.h>
 #include <pthread.h>
 
-#include <cutils/sched_policy.h>
-
 #ifndef SCHED_NORMAL
   #define SCHED_NORMAL 0
 #endif
@@ -124,32 +131,32 @@
 
 #if CAN_SET_SP_SYSTEM
         filename = "/dev/cpuctl/tasks";
-        system_cgroup_fd = open(filename, O_WRONLY);
+        system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (system_cgroup_fd < 0) {
             SLOGV("open of %s failed: %s\n", filename, strerror(errno));
         }
 #endif
 
         filename = "/dev/cpuctl/foreground/tasks";
-        fg_cgroup_fd = open(filename, O_WRONLY);
+        fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (fg_cgroup_fd < 0) {
             SLOGE("open of %s failed: %s\n", filename, strerror(errno));
         }
 
         filename = "/dev/cpuctl/bg_non_interactive/tasks";
-        bg_cgroup_fd = open(filename, O_WRONLY);
+        bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (bg_cgroup_fd < 0) {
             SLOGE("open of %s failed: %s\n", filename, strerror(errno));
         }
 
         filename = "/dev/cpuctl/audio_app/tasks";
-        audio_app_cgroup_fd = open(filename, O_WRONLY);
+        audio_app_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (audio_app_cgroup_fd < 0) {
             SLOGV("open of %s failed: %s\n", filename, strerror(errno));
         }
 
         filename = "/dev/cpuctl/audio_sys/tasks";
-        audio_sys_cgroup_fd = open(filename, O_WRONLY);
+        audio_sys_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (audio_sys_cgroup_fd < 0) {
             SLOGV("open of %s failed: %s\n", filename, strerror(errno));
         }
@@ -274,15 +281,6 @@
     return 0;
 }
 
-/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
- * Call this any place a SchedPolicy is used as an input parameter.
- * Returns the possibly re-mapped policy.
- */
-static inline SchedPolicy _policy(SchedPolicy p)
-{
-   return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
-}
-
 int set_sched_policy(int tid, SchedPolicy policy)
 {
 #ifdef HAVE_GETTID
@@ -356,6 +354,23 @@
     return 0;
 }
 
+#else
+
+/* Stubs for non-Android targets. */
+
+int set_sched_policy(int tid, SchedPolicy policy)
+{
+    return 0;
+}
+
+int get_sched_policy(int tid, SchedPolicy *policy)
+{
+    *policy = SP_SYSTEM_DEFAULT;
+    return 0;
+}
+
+#endif
+
 const char *get_sched_policy_name(SchedPolicy policy)
 {
     policy = _policy(policy);
@@ -372,5 +387,3 @@
         return "error";
 }
 
-#endif /* HAVE_PTHREADS */
-#endif /* HAVE_SCHED_H */
diff --git a/liblog/Android.mk b/liblog/Android.mk
index bd2590e..be5cec2 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -41,7 +41,7 @@
 liblog_host_sources := $(liblog_sources) fake_log_device.c
 
 
-# Static library for host
+# Shared and static library for host
 # ========================================================
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_host_sources)
@@ -49,6 +49,11 @@
 LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
 include $(BUILD_HOST_STATIC_LIBRARY)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := liblog
+include $(BUILD_HOST_SHARED_LIBRARY)
+
 
 # Static library for host, 64-bit
 # ========================================================
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
new file mode 100644
index 0000000..45cb701
--- /dev/null
+++ b/libsuspend/Android.mk
@@ -0,0 +1,23 @@
+# Copyright 2012 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+libsuspend_src_files := \
+	autosuspend.c \
+	autosuspend_autosleep.c \
+	autosuspend_earlysuspend.c \
+	autosuspend_wakeup_count.c \
+
+libsuspend_libraries := \
+	liblog libcutils
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(libsuspend_src_files)
+LOCAL_MODULE := libsuspend
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
+#LOCAL_CFLAGS += -DLOG_NDEBUG=0
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
new file mode 100644
index 0000000..7d1d973
--- /dev/null
+++ b/libsuspend/autosuspend.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdbool.h>
+
+#define LOG_TAG "libsuspend"
+#include <cutils/log.h>
+
+#include <suspend/autosuspend.h>
+
+#include "autosuspend_ops.h"
+
+static struct autosuspend_ops *autosuspend_ops;
+static bool autosuspend_enabled;
+static bool autosuspend_inited;
+
+static int autosuspend_init(void)
+{
+    if (autosuspend_inited) {
+        return 0;
+    }
+
+    autosuspend_inited = true;
+
+    autosuspend_ops = autosuspend_earlysuspend_init();
+    if (autosuspend_ops) {
+        goto out;
+    }
+
+    autosuspend_ops = autosuspend_autosleep_init();
+    if (autosuspend_ops) {
+        goto out;
+    }
+
+    autosuspend_ops = autosuspend_wakeup_count_init();
+    if (autosuspend_ops) {
+        goto out;
+    }
+
+    if (!autosuspend_ops) {
+        ALOGE("failed to initialize autosuspend\n");
+        return -1;
+    }
+
+out:
+    ALOGV("autosuspend initialized\n");
+    return 0;
+}
+
+int autosuspend_enable(void)
+{
+    int ret;
+
+    ret = autosuspend_init();
+    if (ret) {
+        return ret;
+    }
+
+    ALOGV("autosuspend_enable\n");
+
+    if (autosuspend_enabled) {
+        return 0;
+    }
+
+    ret = autosuspend_ops->enable();
+    if (ret) {
+        return ret;
+    }
+
+    autosuspend_enabled = true;
+    return 0;
+}
+
+int autosuspend_disable(void)
+{
+    int ret;
+
+    ret = autosuspend_init();
+    if (ret) {
+        return ret;
+    }
+
+    ALOGV("autosuspend_disable\n");
+
+    if (!autosuspend_enabled) {
+        return 0;
+    }
+
+    ret = autosuspend_ops->disable();
+    if (ret) {
+        return ret;
+    }
+
+    autosuspend_enabled = false;
+    return 0;
+}
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
new file mode 100644
index 0000000..dd0dfef
--- /dev/null
+++ b/libsuspend/autosuspend_autosleep.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define LOG_TAG "libsuspend"
+#include <cutils/log.h>
+
+#include "autosuspend_ops.h"
+
+#define SYS_POWER_AUTOSLEEP "/sys/power/autosleep"
+
+static int autosleep_fd;
+static const char *sleep_state = "mem";
+static const char *on_state = "off";
+
+static int autosuspend_autosleep_enable(void)
+{
+    char buf[80];
+    int ret;
+
+    ALOGV("autosuspend_autosleep_enable\n");
+
+    ret = write(autosleep_fd, sleep_state, strlen(sleep_state));
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
+        goto err;
+    }
+
+    ALOGV("autosuspend_autosleep_enable done\n");
+
+    return 0;
+
+err:
+    return ret;
+}
+
+static int autosuspend_autosleep_disable(void)
+{
+    char buf[80];
+    int ret;
+
+    ALOGV("autosuspend_autosleep_disable\n");
+
+    ret = write(autosleep_fd, on_state, strlen(on_state));
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
+        goto err;
+    }
+
+    ALOGV("autosuspend_autosleep_disable done\n");
+
+    return 0;
+
+err:
+    return ret;
+}
+
+struct autosuspend_ops autosuspend_autosleep_ops = {
+        .enable = autosuspend_autosleep_enable,
+        .disable = autosuspend_autosleep_disable,
+};
+
+struct autosuspend_ops *autosuspend_autosleep_init(void)
+{
+    int ret;
+    char buf[80];
+
+    autosleep_fd = open(SYS_POWER_AUTOSLEEP, O_WRONLY);
+    if (autosleep_fd < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
+        return NULL;
+    }
+
+    ALOGI("Selected autosleep\n");
+    return &autosuspend_autosleep_ops;
+}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
new file mode 100644
index 0000000..2c2aa36
--- /dev/null
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define LOG_TAG "libsuspend"
+#include <cutils/log.h>
+
+#include "autosuspend_ops.h"
+
+#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
+#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
+#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
+
+
+static int sPowerStatefd;
+static const char *pwr_state_mem = "mem";
+static const char *pwr_state_on = "on";
+
+static int autosuspend_earlysuspend_enable(void)
+{
+    char buf[80];
+    int ret;
+
+    ALOGV("autosuspend_earlysuspend_enable\n");
+
+    ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
+        goto err;
+    }
+
+    ALOGV("autosuspend_earlysuspend_enable done\n");
+
+    return 0;
+
+err:
+    return ret;
+}
+
+static int autosuspend_earlysuspend_disable(void)
+{
+    char buf[80];
+    int ret;
+
+    ALOGV("autosuspend_earlysuspend_disable\n");
+
+    ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
+        goto err;
+    }
+
+    ALOGV("autosuspend_earlysuspend_disable done\n");
+
+    return 0;
+
+err:
+    return ret;
+}
+
+struct autosuspend_ops autosuspend_earlysuspend_ops = {
+        .enable = autosuspend_earlysuspend_enable,
+        .disable = autosuspend_earlysuspend_disable,
+};
+
+struct autosuspend_ops *autosuspend_earlysuspend_init(void)
+{
+    char buf[80];
+    int ret;
+
+    ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
+    if (ret < 0) {
+        return NULL;
+    }
+
+    ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
+    if (ret < 0) {
+        return NULL;
+    }
+
+    sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
+
+    if (sPowerStatefd < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
+        return NULL;
+    }
+
+    ALOGI("Selected early suspend\n");
+    return &autosuspend_earlysuspend_ops;
+}
diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
new file mode 100644
index 0000000..698e25b
--- /dev/null
+++ b/libsuspend/autosuspend_ops.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBSUSPEND_AUTOSUSPEND_OPS_H_
+#define _LIBSUSPEND_AUTOSUSPEND_OPS_H_
+
+struct autosuspend_ops {
+    int (*enable)(void);
+    int (*disable)(void);
+};
+
+struct autosuspend_ops *autosuspend_autosleep_init(void);
+struct autosuspend_ops *autosuspend_earlysuspend_init(void);
+struct autosuspend_ops *autosuspend_wakeup_count_init(void);
+
+#endif
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
new file mode 100644
index 0000000..b038e20
--- /dev/null
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define LOG_TAG "libsuspend"
+#include <cutils/log.h>
+
+#include "autosuspend_ops.h"
+
+#define SYS_POWER_STATE "/sys/power/state"
+#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
+
+static int state_fd;
+static int wakeup_count_fd;
+static pthread_t suspend_thread;
+static sem_t suspend_lockout;
+static const char *sleep_state = "mem";
+
+static void *suspend_thread_func(void *arg)
+{
+    char buf[80];
+    char wakeup_count[20];
+    int wakeup_count_len;
+    int ret;
+
+    while (1) {
+        usleep(100000);
+        ALOGV("%s: read wakeup_count\n", __func__);
+        lseek(wakeup_count_fd, 0, SEEK_SET);
+        wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count));
+        if (wakeup_count_len < 0) {
+            strerror_r(errno, buf, sizeof(buf));
+            ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
+            wakeup_count_len = 0;
+            continue;
+        }
+        if (!wakeup_count_len) {
+            ALOGE("Empty wakeup count\n");
+            continue;
+        }
+
+        ALOGV("%s: wait\n", __func__);
+        ret = sem_wait(&suspend_lockout);
+        if (ret < 0) {
+            strerror_r(errno, buf, sizeof(buf));
+            ALOGE("Error waiting on semaphore: %s\n", buf);
+            continue;
+        }
+
+        ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
+        ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len);
+        if (ret < 0) {
+            strerror_r(errno, buf, sizeof(buf));
+            ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
+        } else {
+            ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
+            ret = write(state_fd, sleep_state, strlen(sleep_state));
+            if (ret < 0) {
+                strerror_r(errno, buf, sizeof(buf));
+                ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
+            }
+        }
+
+        ALOGV("%s: release sem\n", __func__);
+        ret = sem_post(&suspend_lockout);
+        if (ret < 0) {
+            strerror_r(errno, buf, sizeof(buf));
+            ALOGE("Error releasing semaphore: %s\n", buf);
+        }
+    }
+    return NULL;
+}
+
+static int autosuspend_wakeup_count_enable(void)
+{
+    char buf[80];
+    int ret;
+
+    ALOGV("autosuspend_wakeup_count_enable\n");
+
+    ret = sem_post(&suspend_lockout);
+
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error changing semaphore: %s\n", buf);
+    }
+
+    ALOGV("autosuspend_wakeup_count_enable done\n");
+
+    return ret;
+}
+
+static int autosuspend_wakeup_count_disable(void)
+{
+    char buf[80];
+    int ret;
+
+    ALOGV("autosuspend_wakeup_count_disable\n");
+
+    ret = sem_wait(&suspend_lockout);
+
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error changing semaphore: %s\n", buf);
+    }
+
+    ALOGV("autosuspend_wakeup_count_disable done\n");
+
+    return ret;
+}
+
+struct autosuspend_ops autosuspend_wakeup_count_ops = {
+        .enable = autosuspend_wakeup_count_enable,
+        .disable = autosuspend_wakeup_count_disable,
+};
+
+struct autosuspend_ops *autosuspend_wakeup_count_init(void)
+{
+    int ret;
+    char buf[80];
+
+    state_fd = open(SYS_POWER_STATE, O_RDWR);
+    if (state_fd < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf);
+        goto err_open_state;
+    }
+
+    wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR);
+    if (wakeup_count_fd < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
+        goto err_open_wakeup_count;
+    }
+
+    ret = sem_init(&suspend_lockout, 0, 0);
+    if (ret < 0) {
+        strerror_r(errno, buf, sizeof(buf));
+        ALOGE("Error creating semaphore: %s\n", buf);
+        goto err_sem_init;
+    }
+    ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
+    if (ret) {
+        strerror_r(ret, buf, sizeof(buf));
+        ALOGE("Error creating thread: %s\n", buf);
+        goto err_pthread_create;
+    }
+
+    ALOGI("Selected wakeup count\n");
+    return &autosuspend_wakeup_count_ops;
+
+err_pthread_create:
+    sem_destroy(&suspend_lockout);
+err_sem_init:
+    close(wakeup_count_fd);
+err_open_wakeup_count:
+    close(state_fd);
+err_open_state:
+    return NULL;
+}
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
new file mode 100644
index 0000000..f56fc6a
--- /dev/null
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBSUSPEND_AUTOSUSPEND_H_
+#define _LIBSUSPEND_AUTOSUSPEND_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * autosuspend_enable
+ *
+ * Turn on autosuspend in the kernel, allowing it to enter suspend if no
+ * wakelocks/wakeup_sources are held.
+ *
+ *
+ *
+ * Returns 0 on success, -1 if autosuspend was not enabled.
+ */
+int autosuspend_enable(void);
+
+/*
+ * autosuspend_disable
+ *
+ * Turn off autosuspend in the kernel, preventing suspend and synchronizing
+ * with any in-progress resume.
+ *
+ * Returns 0 on success, -1 if autosuspend was not disabled.
+ */
+int autosuspend_disable(void);
+
+__END_DECLS
+
+#endif
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7924a44..05b7621 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -97,7 +97,7 @@
     chown system system /dev/cpuctl/foreground/tasks
     chmod 0666 /dev/cpuctl/foreground/tasks
     write /dev/cpuctl/foreground/cpu.shares 1024
-    write /dev/cpuctl/foreground/cpu.rt_runtime_us 0
+    write /dev/cpuctl/foreground/cpu.rt_runtime_us 1000
     write /dev/cpuctl/foreground/cpu.rt_period_us 1000000
 
     mkdir /dev/cpuctl/bg_non_interactive
@@ -105,7 +105,7 @@
     chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
     # 5.0 %
     write /dev/cpuctl/bg_non_interactive/cpu.shares 52
-    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 0
+    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 1000
     write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
 
     mkdir /dev/cpuctl/audio_app