OSDN Git Service

vulkan: Updated IHV documentation
authorJesse Hall <jessehall@google.com>
Sat, 18 Jun 2016 01:56:55 +0000 (01:56 +0000)
committerandroid-build-merger <android-build-merger@google.com>
Sat, 18 Jun 2016 01:56:55 +0000 (01:56 +0000)
am: c2f184d9d8

Change-Id: I4ca9873ec84e5e02e6bb5e303dbce4604cd43e6f

62 files changed:
cmds/dumpstate/dumpstate.cpp
cmds/installd/commands.cpp
cmds/installd/commands.h
cmds/installd/installd.cpp
cmds/installd/installd_constants.h
cmds/installd/otapreopt.cpp
cmds/installd/otapreopt_chroot.cpp
cmds/installd/otapreopt_script.sh
cmds/installd/string_helpers.h [deleted file]
data/etc/wearable_core_hardware.xml
include/android/keycodes.h
include/gui/BufferQueue.h
include/gui/BufferQueueConsumer.h
include/gui/BufferQueueCore.h
include/gui/BufferQueueProducer.h
include/gui/ConsumerBase.h
include/gui/FrameTimestamps.h [new file with mode: 0644]
include/gui/IConsumerListener.h
include/gui/IGraphicBufferConsumer.h
include/gui/IGraphicBufferProducer.h
include/gui/OccupancyTracker.h [new file with mode: 0644]
include/gui/Surface.h
include/input/InputEventLabels.h
include/ui/Gralloc1.h [new file with mode: 0644]
include/ui/Gralloc1On0Adapter.h [new file with mode: 0644]
include/ui/GraphicBufferAllocator.h
include/ui/GraphicBufferMapper.h
libs/gui/Android.mk
libs/gui/BufferQueue.cpp
libs/gui/BufferQueueConsumer.cpp
libs/gui/BufferQueueProducer.cpp
libs/gui/ConsumerBase.cpp
libs/gui/IConsumerListener.cpp
libs/gui/IGraphicBufferConsumer.cpp
libs/gui/IGraphicBufferProducer.cpp
libs/gui/OccupancyTracker.cpp [new file with mode: 0644]
libs/gui/Surface.cpp
libs/gui/tests/BufferQueue_test.cpp
libs/ui/Android.mk
libs/ui/Gralloc1.cpp [new file with mode: 0644]
libs/ui/Gralloc1On0Adapter.cpp [new file with mode: 0644]
libs/ui/GraphicBuffer.cpp
libs/ui/GraphicBufferAllocator.cpp
libs/ui/GraphicBufferMapper.cpp
opengl/libagl/context.h
opengl/libagl/egl.cpp
opengl/libagl/light.cpp
opengl/libagl/matrix.cpp
opengl/libagl/texture.cpp
services/inputflinger/InputReader.cpp
services/surfaceflinger/Android.mk
services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
services/surfaceflinger/FenceTracker.cpp
services/surfaceflinger/FenceTracker.h
services/surfaceflinger/Layer.cpp
services/surfaceflinger/Layer.h
services/surfaceflinger/SurfaceFlinger.cpp
services/surfaceflinger/SurfaceFlinger.h
services/surfaceflinger/SurfaceFlingerConsumer.cpp
services/surfaceflinger/SurfaceFlingerConsumer.h
services/surfaceflinger/SurfaceFlinger_hwc1.cpp
services/surfaceflinger/surfaceflinger.rc

index b9c9e75..3376dfe 100644 (file)
@@ -54,7 +54,7 @@ using android::base::StringPrintf;
 static char cmdline_buf[16384] = "(unknown)";
 static const char *dump_traces_path = NULL;
 
-// TODO: should be part of dumpstate object
+// TODO: variables below should be part of dumpstate object
 static unsigned long id;
 static char build_type[PROPERTY_VALUE_MAX];
 static time_t now;
@@ -68,7 +68,7 @@ static std::string suffix;
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 
-#define RAFT_DIR "/data/misc/raft/"
+#define RAFT_DIR "/data/misc/raft"
 #define RECOVERY_DIR "/cache/recovery"
 #define RECOVERY_DATA_DIR "/data/misc/recovery"
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
@@ -217,6 +217,40 @@ static void dump_systrace() {
     }
 }
 
+static void dump_raft() {
+    if (is_user_build()) {
+        return;
+    }
+
+    std::string raft_log_path = bugreport_dir + "/raft_log.txt";
+    if (raft_log_path.empty()) {
+        MYLOGD("raft_log_path is empty\n");
+        return;
+    }
+
+    struct stat s;
+    if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
+        MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
+        return;
+    }
+
+    if (!zip_writer) {
+        // Write compressed and encoded raft logs to stdout if not zip_writer.
+        run_command("RAFT LOGS", 600, "logcompressor", "-r", RAFT_DIR, NULL);
+        return;
+    }
+
+    run_command("RAFT LOGS", 600, "logcompressor", "-n", "-r", RAFT_DIR,
+            "-o", raft_log_path.c_str(), NULL);
+    if (!add_zip_entry("raft_log.txt", raft_log_path)) {
+        MYLOGE("Unable to add raft log %s to zip file\n", raft_log_path.c_str());
+    } else {
+        if (remove(raft_log_path.c_str())) {
+            MYLOGE("Error removing raft file %s: %s\n", raft_log_path.c_str(), strerror(errno));
+        }
+    }
+}
+
 static bool skip_not_stat(const char *path) {
     static const char stat[] = "/stat";
     size_t len = strlen(path);
@@ -505,7 +539,7 @@ static void print_header(std::string version) {
     property_get("ro.build.display.id", build, "(unknown)");
     property_get("ro.build.fingerprint", fingerprint, "(unknown)");
     property_get("ro.build.type", build_type, "(unknown)");
-    property_get("ro.baseband", radio, "(unknown)");
+    property_get("gsm.version.baseband", radio, "(unknown)");
     property_get("ro.bootloader", bootloader, "(unknown)");
     property_get("gsm.operator.alpha", network, "(unknown)");
     strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
@@ -529,18 +563,39 @@ static void print_header(std::string version) {
     printf("\n");
 }
 
+// List of file extensions that can cause a zip file attachment to be rejected by some email
+// service providers.
+static const std::set<std::string> PROBLEMATIC_FILE_EXTENSIONS = {
+      ".ade", ".adp", ".bat", ".chm", ".cmd", ".com", ".cpl", ".exe", ".hta", ".ins", ".isp",
+      ".jar", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msp", ".mst", ".pif", ".scr", ".sct",
+      ".shb", ".sys", ".vb",  ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
+};
+
 bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
     if (!zip_writer) {
         MYLOGD("Not adding zip entry %s from fd because zip_writer is not set\n",
                 entry_name.c_str());
         return false;
     }
+    std::string valid_name = entry_name;
+
+    // Rename extension if necessary.
+    size_t idx = entry_name.rfind(".");
+    if (idx != std::string::npos) {
+        std::string extension = entry_name.substr(idx);
+        std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+        if (PROBLEMATIC_FILE_EXTENSIONS.count(extension) != 0) {
+            valid_name = entry_name + ".renamed";
+            MYLOGI("Renaming entry %s to %s\n", entry_name.c_str(), valid_name.c_str());
+        }
+    }
+
     // Logging statement  below is useful to time how long each entry takes, but it's too verbose.
     // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(),
+    int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
             ZipWriter::kCompress, get_mtime(fd, now));
     if (err) {
-        MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
+        MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
                 ZipWriter::ErrorCodeString(err));
         return false;
     }
@@ -585,6 +640,7 @@ static int _add_file_from_fd(const char *title, const char *path, int fd) {
     return add_zip_entry_from_fd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
 }
 
+// TODO: move to util.cpp
 void add_dir(const char *dir, bool recursive) {
     if (!zip_writer) {
         MYLOGD("Not adding dir %s because zip_writer is not set\n", dir);
@@ -699,8 +755,6 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver
 
     run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
 
-    run_command("RAFT LOGS", 600, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL);
-
     /* show the traces we collected in main(), if that was done */
     if (dump_traces_path != NULL) {
         dump_file("VM TRACES JUST NOW", dump_traces_path);
@@ -921,7 +975,7 @@ static void dumpstate(const std::string& screenshot_path, const std::string& ver
     printf("== Running Application Providers\n");
     printf("========================================================\n");
 
-    run_command("APP SERVICES", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
+    run_command("APP PROVIDERS", 30, "dumpsys", "-t", "30", "activity", "provider", "all", NULL);
 
 
     printf("========================================================\n");
@@ -1273,6 +1327,9 @@ int main(int argc, char *argv[]) {
     // Dumps systrace right away, otherwise it will be filled with unnecessary events.
     dump_systrace();
 
+    // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
+    dump_raft();
+
     // Invoking the following dumpsys calls before dump_traces() to try and
     // keep the system stats as close to its initial state as possible.
     run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
index 2a9950a..8999441 100644 (file)
@@ -28,9 +28,9 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/log.h>               // TODO: Move everything to base/logging.
@@ -49,6 +49,7 @@
 #define LOG_TAG "installd"
 #endif
 
+using android::base::EndsWith;
 using android::base::StringPrintf;
 
 namespace android {
@@ -1313,13 +1314,29 @@ bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string)
     return true;
 }
 
-static void trim_extension(char* path) {
-  // Trim the extension.
-  int pos = strlen(path);
-  for (; pos >= 0 && path[pos] != '.'; --pos) {}
-  if (pos >= 0) {
-      path[pos] = '\0';  // Trim extension
+// Translate the given oat path to an art (app image) path. An empty string
+// denotes an error.
+static std::string create_image_filename(const std::string& oat_path) {
+  // A standard dalvik-cache entry. Replace ".dex" with ".art."
+  if (EndsWith(oat_path, ".dex")) {
+    std::string art_path = oat_path;
+    art_path.replace(art_path.length() - strlen("dex"), strlen("dex"), "art");
+    CHECK(EndsWith(art_path, ".art"));
+    return art_path;
+  }
+
+  // An odex entry. Not that this may not be an extension, e.g., in the OTA
+  // case (where the base name will have an extension for the B artifact).
+  size_t odex_pos = oat_path.rfind(".odex");
+  if (odex_pos != std::string::npos) {
+    std::string art_path = oat_path;
+    art_path.replace(odex_pos, strlen(".odex"), ".art");
+    CHECK_NE(art_path.find(".art"), std::string::npos);
+    return art_path;
   }
+
+  // Don't know how to handle this.
+  return "";
 }
 
 static bool add_extension_to_file_name(char* file_name, const char* extension) {
@@ -1330,7 +1347,7 @@ static bool add_extension_to_file_name(char* file_name, const char* extension) {
     return true;
 }
 
-static int open_output_file(char* file_name, bool recreate, int permissions) {
+static int open_output_file(const char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
         if (unlink(file_name) < 0) {
@@ -1388,19 +1405,110 @@ bool merge_profiles(uid_t uid, const char *pkgname) {
     return analyse_profiles(uid, pkgname);
 }
 
+static const char* parse_null(const char* arg) {
+    if (strcmp(arg, "!") == 0) {
+        return nullptr;
+    } else {
+        return arg;
+    }
+}
+
+int dexopt(const char* params[DEXOPT_PARAM_COUNT]) {
+    return dexopt(params[0],                    // apk_path
+                  atoi(params[1]),              // uid
+                  params[2],                    // pkgname
+                  params[3],                    // instruction_set
+                  atoi(params[4]),              // dexopt_needed
+                  params[5],                    // oat_dir
+                  atoi(params[6]),              // dexopt_flags
+                  params[7],                    // compiler_filter
+                  parse_null(params[8]),        // volume_uuid
+                  parse_null(params[9]));       // shared_libraries
+    static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param count");
+}
+
+// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
+// on destruction. It will also run the given cleanup (unless told not to) after closing.
+//
+// Usage example:
+//
+//   Dex2oatFileWrapper<std::function<void ()>> file(open(...),
+//                                                   [name]() {
+//                                                       unlink(name.c_str());
+//                                                   });
+//   // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
+//            wrapper if captured as a reference.
+//
+//   if (file.get() == -1) {
+//       // Error opening...
+//   }
+//
+//   ...
+//   if (error) {
+//       // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
+//       // and delete the file (after the fd is closed).
+//       return -1;
+//   }
+//
+//   (Success case)
+//   file.SetCleanup(false);
+//   // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
+//   // (leaving the file around; after the fd is closed).
+//
+template <typename Cleanup>
+class Dex2oatFileWrapper {
+ public:
+    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
+    }
+
+    Dex2oatFileWrapper(int value, Cleanup cleanup)
+            : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
+
+    ~Dex2oatFileWrapper() {
+        reset(-1);
+    }
+
+    int get() {
+        return value_;
+    }
+
+    void SetCleanup(bool cleanup) {
+        do_cleanup_ = cleanup;
+    }
+
+    void reset(int new_value) {
+        if (value_ >= 0) {
+            close(value_);
+        }
+        if (do_cleanup_ && cleanup_ != nullptr) {
+            cleanup_();
+        }
+
+        value_ = new_value;
+    }
+
+    void reset(int new_value, Cleanup new_cleanup) {
+        if (value_ >= 0) {
+            close(value_);
+        }
+        if (do_cleanup_ && cleanup_ != nullptr) {
+            cleanup_();
+        }
+
+        value_ = new_value;
+        cleanup_ = new_cleanup;
+    }
+
+ private:
+    int value_;
+    Cleanup cleanup_;
+    bool do_cleanup_;
+};
+
 int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
            int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
            const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries)
 {
-    struct utimbuf ut;
-    struct stat input_stat;
-    char out_path[PKG_PATH_MAX];
-    char swap_file_name[PKG_PATH_MAX];
-    char image_path[PKG_PATH_MAX];
-    const char *input_file;
-    char in_odex_path[PKG_PATH_MAX];
-    int res;
-    fd_t input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1;
     bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
     bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
@@ -1410,12 +1518,16 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
 
-    fd_t reference_profile_fd = -1;
     // Public apps should not be compiled with profile information ever. Same goes for the special
     // package '*' used for the system server.
+    Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
     if (!is_public && pkgname[0] != '*') {
         // Open reference profile in read only mode as dex2oat does not get write permissions.
-        reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
+        const std::string pkgname_str(pkgname);
+        reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
+                                   [pkgname_str]() {
+                                       clear_reference_profile(pkgname_str.c_str());
+                                   });
         // Note: it's OK to not find a profile here.
     }
 
@@ -1423,10 +1535,13 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins
         LOG_FATAL("dexopt flags contains unknown fields\n");
     }
 
+    char out_path[PKG_PATH_MAX];
     if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
         return false;
     }
 
+    const char *input_file;
+    char in_odex_path[PKG_PATH_MAX];
     switch (dexopt_needed) {
         case DEXOPT_DEX2OAT_NEEDED:
             input_file = apk_path;
@@ -1445,35 +1560,41 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins
 
         default:
             ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
-            exit(72);
+            return 72;
     }
 
+    struct stat input_stat;
     memset(&input_stat, 0, sizeof(input_stat));
     stat(input_file, &input_stat);
 
-    input_fd = open(input_file, O_RDONLY, 0);
-    if (input_fd < 0) {
+    base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
+    if (input_fd.get() < 0) {
         ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
         return -1;
     }
 
-    out_fd = open_output_file(out_path, /*recreate*/true, /*permissions*/0644);
-    if (out_fd < 0) {
+    const std::string out_path_str(out_path);
+    Dex2oatFileWrapper<std::function<void ()>> out_fd(
+            open_output_file(out_path, /*recreate*/true, /*permissions*/0644),
+            [out_path_str]() { unlink(out_path_str.c_str()); });
+    if (out_fd.get() < 0) {
         ALOGE("installd cannot open '%s' for output during dexopt\n", out_path);
-        goto fail;
+        return -1;
     }
-    if (!set_permissions_and_ownership(out_fd, is_public, uid, out_path)) {
-        goto fail;
+    if (!set_permissions_and_ownership(out_fd.get(), is_public, uid, out_path)) {
+        return -1;
     }
 
     // Create a swap file if necessary.
+    base::unique_fd swap_fd;
     if (ShouldUseSwapFileForDexopt()) {
         // Make sure there really is enough space.
+        char swap_file_name[PKG_PATH_MAX];
         strcpy(swap_file_name, out_path);
         if (add_extension_to_file_name(swap_file_name, ".swap")) {
-            swap_fd = open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600);
+            swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
         }
-        if (swap_fd < 0) {
+        if (swap_fd.get() < 0) {
             // Could not create swap file. Optimistically go on and hope that we can compile
             // without it.
             ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
@@ -1486,111 +1607,108 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins
     }
 
     // Avoid generating an app image for extract only since it will not contain any classes.
-    strcpy(image_path, out_path);
-    trim_extension(image_path);
-    if (add_extension_to_file_name(image_path, ".art")) {
-      char app_image_format[kPropertyValueMax];
-      bool have_app_image_format =
-              get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-      // Use app images only if it is enabled (by a set image format) and we are compiling
-      // profile-guided (so the app image doesn't conservatively contain all classes).
-      if (profile_guided && have_app_image_format) {
-          // Recreate is true since we do not want to modify a mapped image. If the app is already
-          // running and we modify the image file, it can cause crashes (b/27493510).
-          image_fd = open_output_file(image_path, /*recreate*/true, /*permissions*/0600);
-          if (image_fd < 0) {
-              // Could not create application image file. Go on since we can compile without it.
-              ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
-          } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) {
-              image_fd = -1;
-          }
-      }
-      // If we have a valid image file path but no image fd, erase the image file.
-      if (image_fd < 0) {
-          if (unlink(image_path) < 0) {
-              if (errno != ENOENT) {
-                  PLOG(ERROR) << "Couldn't unlink image file " << image_path;
-              }
-          }
-      }
+    Dex2oatFileWrapper<std::function<void ()>> image_fd;
+    const std::string image_path = create_image_filename(out_path);
+    if (!image_path.empty()) {
+        char app_image_format[kPropertyValueMax];
+        bool have_app_image_format =
+                get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+        // Use app images only if it is enabled (by a set image format) and we are compiling
+        // profile-guided (so the app image doesn't conservatively contain all classes).
+        if (profile_guided && have_app_image_format) {
+            // Recreate is true since we do not want to modify a mapped image. If the app is
+            // already running and we modify the image file, it can cause crashes (b/27493510).
+            image_fd.reset(open_output_file(image_path.c_str(),
+                                            true /*recreate*/,
+                                            0600 /*permissions*/),
+                           [image_path]() { unlink(image_path.c_str()); }
+                           );
+            if (image_fd.get() < 0) {
+                // Could not create application image file. Go on since we can compile without
+                // it.
+                LOG(ERROR) << "installd could not create '"
+                        << image_path
+                        << "' for image file during dexopt";
+            } else if (!set_permissions_and_ownership(image_fd.get(),
+                                                      is_public,
+                                                      uid,
+                                                      image_path.c_str())) {
+                image_fd.reset(-1);
+            }
+        }
+        // If we have a valid image file path but no image fd, explicitly erase the image file.
+        if (image_fd.get() < 0) {
+            if (unlink(image_path.c_str()) < 0) {
+                if (errno != ENOENT) {
+                    PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+                }
+            }
+        }
     }
 
     ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
 
-    pid_t pid;
-    pid = fork();
+    pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
         SetDex2OatAndPatchOatScheduling(boot_complete);
-        if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
+        if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
-            exit(67);
+            _exit(67);
         }
 
         if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
             || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
-            run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
+            run_patchoat(input_fd.get(),
+                         out_fd.get(),
+                         input_file,
+                         out_path,
+                         pkgname,
+                         instruction_set);
         } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) {
             // Pass dex2oat the relative path to the input file.
             const char *input_file_name = get_location_from_path(input_file);
-            run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd,
-                        instruction_set, compiler_filter, vm_safe_mode, debuggable, boot_complete,
-                        reference_profile_fd, shared_libraries);
+            run_dex2oat(input_fd.get(),
+                        out_fd.get(),
+                        image_fd.get(),
+                        input_file_name,
+                        out_path,
+                        swap_fd.get(),
+                        instruction_set,
+                        compiler_filter,
+                        vm_safe_mode,
+                        debuggable,
+                        boot_complete,
+                        reference_profile_fd.get(),
+                        shared_libraries);
         } else {
             ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
-            exit(73);
+            _exit(73);
         }
-        exit(68);   /* only get here on exec failure */
+        _exit(68);   /* only get here on exec failure */
     } else {
-        res = wait_child(pid);
+        int res = wait_child(pid);
         if (res == 0) {
             ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
         } else {
             ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
-            goto fail;
+            return -1;
         }
     }
 
+    struct utimbuf ut;
     ut.actime = input_stat.st_atime;
     ut.modtime = input_stat.st_mtime;
     utime(out_path, &ut);
 
-    close(out_fd);
-    close(input_fd);
-    if (swap_fd >= 0) {
-        close(swap_fd);
-    }
-    if (reference_profile_fd >= 0) {
-        close(reference_profile_fd);
-    }
-    if (image_fd >= 0) {
-        close(image_fd);
-    }
-    return 0;
+    // We've been successful, don't delete output.
+    out_fd.SetCleanup(false);
+    image_fd.SetCleanup(false);
+    reference_profile_fd.SetCleanup(false);
 
-fail:
-    if (out_fd >= 0) {
-        close(out_fd);
-        unlink(out_path);
-    }
-    if (input_fd >= 0) {
-        close(input_fd);
-    }
-    if (reference_profile_fd >= 0) {
-        close(reference_profile_fd);
-        // We failed to compile. Unlink the reference profile. Current profiles are already unlinked
-        // when profmoan advises compilation.
-        clear_reference_profile(pkgname);
-    }
-    if (swap_fd >= 0) {
-        close(swap_fd);
-    }
-    if (image_fd >= 0) {
-        close(image_fd);
-    }
-    return -1;
+    return 0;
 }
 
 int mark_boot_complete(const char* instruction_set)
@@ -1926,6 +2044,37 @@ static bool unlink_and_rename(const char* from, const char* to) {
     return true;
 }
 
+// Move/rename a B artifact (from) to an A artifact (to).
+static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
+    // Check whether B exists.
+    {
+        struct stat s;
+        if (stat(b_path.c_str(), &s) != 0) {
+            // Silently ignore for now. The service calling this isn't smart enough to understand
+            // lack of artifacts at the moment.
+            return false;
+        }
+        if (!S_ISREG(s.st_mode)) {
+            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
+            // Try to unlink, but swallow errors.
+            unlink(b_path.c_str());
+            return false;
+        }
+    }
+
+    // Rename B to A.
+    if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
+        // Delete the b_path so we don't try again (or fail earlier).
+        if (unlink(b_path.c_str()) != 0) {
+            PLOG(ERROR) << "Could not unlink " << b_path;
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
 int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
     if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) {
         LOG(ERROR) << "Cannot move_ab with null input";
@@ -1944,37 +2093,35 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d
     if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
         return -1;
     }
+    const std::string a_image_path = create_image_filename(a_path);
 
     // B path = A path + ".b"
-    std::string b_path = StringPrintf("%s.b", a_path);
+    const std::string b_path = StringPrintf("%s.b", a_path);
+    const std::string b_image_path = StringPrintf("%s.b", a_image_path.c_str());
 
-    // Check whether B exists.
-    {
-        struct stat s;
-        if (stat(b_path.c_str(), &s) != 0) {
-            // Silently ignore for now. The service calling this isn't smart enough to understand
-            // lack of artifacts at the moment.
-            return -1;
-        }
-        if (!S_ISREG(s.st_mode)) {
-            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
-            // Try to unlink, but swallow errors.
-            unlink(b_path.c_str());
-            return -1;
-        }
-    }
+    bool oat_success = move_ab_path(b_path, a_path);
+    bool success;
 
-    // Rename B to A.
-    if (!unlink_and_rename(b_path.c_str(), a_path)) {
-        // Delete the b_path so we don't try again (or fail earlier).
-        if (unlink(b_path.c_str()) != 0) {
-            PLOG(ERROR) << "Could not unlink " << b_path;
+    if (oat_success) {
+        // Note: we can live without an app image. As such, ignore failure to move the image file.
+        //       If we decide to require the app image, or the app image being moved correctly,
+        //       then change accordingly.
+        constexpr bool kIgnoreAppImageFailure = true;
+
+        bool art_success = true;
+        if (!a_image_path.empty()) {
+            art_success = move_ab_path(b_image_path, a_image_path);
         }
 
-        return -1;
+        success = art_success || kIgnoreAppImageFailure;
+    } else {
+        // Cleanup: delete B image, ignore errors.
+        unlink(b_image_path.c_str());
+
+        success = false;
     }
 
-    return 0;
+    return success ? 0 : -1;
 }
 
 }  // namespace installd
index 7a42c5c..c0c39c5 100644 (file)
@@ -56,9 +56,21 @@ bool merge_profiles(uid_t uid, const char *pkgname);
 
 bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files);
 
-int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
-           int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
-           const char* volume_uuid, const char* shared_libraries);
+int dexopt(const char *apk_path,
+           uid_t uid,
+           const char *pkgName,
+           const char *instruction_set,
+           int dexopt_needed,
+           const char* oat_dir,
+           int dexopt_flags,
+           const char* compiler_filter,
+           const char* volume_uuid,
+           const char* shared_libraries);
+static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param size");
+
+// Helper for the above, converting arguments.
+int dexopt(const char* params[DEXOPT_PARAM_COUNT]);
+
 int mark_boot_complete(const char *instruction_set);
 int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
 int idmap(const char *target_path, const char *overlay_path, uid_t uid);
index 061359e..9d2f71b 100644 (file)
@@ -219,7 +219,8 @@ static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSE
 // We use otapreopt_chroot to get into the chroot.
 static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot";
 
-static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+static int do_ota_dexopt(const char* args[DEXOPT_PARAM_COUNT],
+                         char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
     // Time to fork and run otapreopt.
 
     // Check that the tool exists.
@@ -231,12 +232,14 @@ static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
 
     pid_t pid = fork();
     if (pid == 0) {
-        const char* argv[1 + 9 + 1];
+        const char* argv[1 + DEXOPT_PARAM_COUNT + 1];
         argv[0] = kOtaPreopt;
-        for (size_t i = 1; i <= 9; ++i) {
-            argv[i] = arg[i - 1];
+
+        for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
+            argv[i + 1] = args[i];
         }
-        argv[10] = nullptr;
+
+        argv[DEXOPT_PARAM_COUNT + 1] = nullptr;
 
         execv(argv[0], (char * const *)argv);
         PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed";
@@ -252,22 +255,30 @@ static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
     }
 }
 
+static int do_regular_dexopt(const char* args[DEXOPT_PARAM_COUNT],
+                             char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+    return dexopt(args);
+}
+
+using DexoptFn = int (*)(const char* args[DEXOPT_PARAM_COUNT],
+                         char reply[REPLY_MAX]);
+
 static int do_dexopt(char **arg, char reply[REPLY_MAX])
 {
+    const char* args[DEXOPT_PARAM_COUNT];
+    for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
+        CHECK(arg[i] != nullptr);
+        args[i] = arg[i];
+    }
+
     int dexopt_flags = atoi(arg[6]);
+    DexoptFn dexopt_fn;
     if ((dexopt_flags & DEXOPT_OTA) != 0) {
-      return do_ota_dexopt(arg, reply);
-    }
-    return dexopt(arg[0],                      // apk_path
-                  atoi(arg[1]),                // uid
-                  arg[2],                      // pkgname
-                  arg[3],                      // instruction_set
-                  atoi(arg[4]),                // dexopt_needed
-                  arg[5],                      // oat_dir
-                  dexopt_flags,
-                  arg[7],                      // compiler_filter
-                  parse_null(arg[8]),          // volume_uuid
-                  parse_null(arg[9]));         // shared_libraries
+        dexopt_fn = do_ota_dexopt;
+    } else {
+        dexopt_fn = do_regular_dexopt;
+    }
+    return dexopt_fn(args, reply);
 }
 
 static int do_merge_profiles(char **arg, char reply[REPLY_MAX])
index 8513695..823b8ee 100644 (file)
@@ -21,6 +21,8 @@
 namespace android {
 namespace installd {
 
+constexpr size_t DEXOPT_PARAM_COUNT = 10U;
+
 /* elements combined with a valid package name to form paths */
 
 constexpr const char* PRIMARY_USER_PREFIX = "data/";
index ac511ec..e1cfc9d 100644 (file)
@@ -30,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/fs.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -39,7 +40,6 @@
 #include <file_parsing.h>
 #include <globals.h>
 #include <installd_deps.h>  // Need to fill in requirements of commands.
-#include <string_helpers.h>
 #include <system_properties.h>
 #include <utils.h>
 
 #define TOKEN_MAX     16    /* max number of arguments in buffer */
 #define REPLY_MAX     256   /* largest reply allowed */
 
+using android::base::EndsWith;
+using android::base::Join;
+using android::base::Split;
+using android::base::StartsWith;
 using android::base::StringPrintf;
 
 namespace android {
@@ -188,12 +192,14 @@ private:
 
     bool ReadPackage(int argc ATTRIBUTE_UNUSED, char** argv) {
         size_t index = 0;
-        while (index < ARRAY_SIZE(package_parameters_) &&
+        static_assert(DEXOPT_PARAM_COUNT == ARRAY_SIZE(package_parameters_),
+                      "Unexpected dexopt param count");
+        while (index < DEXOPT_PARAM_COUNT &&
                 argv[index + 1] != nullptr) {
             package_parameters_[index] = argv[index + 1];
             index++;
         }
-        if (index != ARRAY_SIZE(package_parameters_)) {
+        if (index != ARRAY_SIZE(package_parameters_) || argv[index + 1] != nullptr) {
             LOG(ERROR) << "Wrong number of parameters";
             return false;
         }
@@ -295,7 +301,7 @@ private:
         std::vector<std::string> cmd;
         cmd.push_back("/system/bin/dex2oat");
         cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
-        for (const std::string& boot_part : Split(boot_cp, ':')) {
+        for (const std::string& boot_part : Split(boot_cp, ":")) {
             cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
         }
         cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str()));
@@ -324,7 +330,7 @@ private:
         const std::string* extra_opts =
                 system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags");
         if (extra_opts != nullptr) {
-            std::vector<std::string> extra_vals = Split(*extra_opts, ' ');
+            std::vector<std::string> extra_vals = Split(*extra_opts, " ");
             cmd.insert(cmd.end(), extra_vals.begin(), extra_vals.end());
         }
         // TODO: Should we lower this? It's usually set close to max, because
@@ -357,17 +363,50 @@ private:
     }
 
     int RunPreopt() {
-        int ret = dexopt(package_parameters_[0],          // apk_path
-                atoi(package_parameters_[1]),             // uid
-                package_parameters_[2],                   // pkgname
-                package_parameters_[3],                   // instruction_set
-                atoi(package_parameters_[4]),             // dexopt_needed
-                package_parameters_[5],                   // oat_dir
-                atoi(package_parameters_[6]),             // dexopt_flags
-                package_parameters_[7],                   // compiler_filter
-                ParseNull(package_parameters_[8]),        // volume_uuid
-                ParseNull(package_parameters_[9]));       // shared_libraries
-        return ret;
+        // Run the preopt.
+        //
+        // There's one thing we have to be careful about: we may/will be asked to compile an app
+        // living in the system image. This may be a valid request - if the app wasn't compiled,
+        // e.g., if the system image wasn't large enough to include preopted files. However, the
+        // data we have is from the old system, so the driver (the OTA service) can't actually
+        // know. Thus, we will get requests for apps that have preopted components. To avoid
+        // duplication (we'd generate files that are not used and are *not* cleaned up), do two
+        // simple checks:
+        //
+        // 1) Does the apk_path start with the value of ANDROID_ROOT? (~in the system image)
+        //    (For simplicity, assume the value of ANDROID_ROOT does not contain a symlink.)
+        //
+        // 2) If you replace the name in the apk_path with "oat," does the path exist?
+        //    (=have a subdirectory for preopted files)
+        //
+        // If the answer to both is yes, skip the dexopt.
+        //
+        // Note: while one may think it's OK to call dexopt and it will fail (because APKs should
+        //       be stripped), that's not true for APKs signed outside the build system (so the
+        //       jar content must be exactly the same).
+
+        //       (This is ugly as it's the only thing where we need to understand the contents
+        //        of package_parameters_, but it beats postponing the decision or using the call-
+        //        backs to do weird things.)
+        constexpr size_t kApkPathIndex = 0;
+        CHECK_GT(DEXOPT_PARAM_COUNT, kApkPathIndex);
+        CHECK(package_parameters_[kApkPathIndex] != nullptr);
+        CHECK(system_properties_.GetProperty(kAndroidRootPathPropertyName) != nullptr);
+        if (StartsWith(package_parameters_[kApkPathIndex],
+                       system_properties_.GetProperty(kAndroidRootPathPropertyName)->c_str())) {
+            const char* last_slash = strrchr(package_parameters_[kApkPathIndex], '/');
+            if (last_slash != nullptr) {
+                std::string path(package_parameters_[kApkPathIndex],
+                                 last_slash - package_parameters_[kApkPathIndex] + 1);
+                CHECK(EndsWith(path, "/"));
+                path = path + "oat";
+                if (access(path.c_str(), F_OK) == 0) {
+                    return 0;
+                }
+            }
+        }
+
+        return dexopt(package_parameters_);
     }
 
     ////////////////////////////////////
@@ -376,7 +415,7 @@ private:
 
     // Wrapper on fork/execv to run a command in a subprocess.
     bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
-        const std::string command_line(Join(arg_vector, ' '));
+        const std::string command_line = Join(arg_vector, ' ');
 
         CHECK_GE(arg_vector.size(), 1U) << command_line;
 
@@ -484,7 +523,7 @@ private:
     // to compile, instead of the A properties we could get from init/get_property.
     SystemProperties system_properties_;
 
-    const char* package_parameters_[10];
+    const char* package_parameters_[DEXOPT_PARAM_COUNT];
 
     // Store environment values we need to set.
     std::vector<std::string> environ_;
@@ -497,7 +536,6 @@ OTAPreoptService gOps;
 ////////////////////////
 
 int get_property(const char *key, char *value, const char *default_value) {
-    // TODO: Replace with system-properties map.
     return gOps.GetProperty(key, value, default_value);
 }
 
@@ -505,9 +543,8 @@ int get_property(const char *key, char *value, const char *default_value) {
 bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir,
                              const char *apk_path,
                              const char *instruction_set) {
-    // TODO: Insert B directory.
-    char *file_name_start;
-    char *file_name_end;
+    const char *file_name_start;
+    const char *file_name_end;
 
     file_name_start = strrchr(apk_path, '/');
     if (file_name_start == nullptr) {
index f7f69a9..be0ff2e 100644 (file)
@@ -22,6 +22,8 @@
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 
+#include <installd_constants.h>
+
 #ifndef LOG_TAG
 #define LOG_TAG "otapreopt"
 #endif
@@ -78,13 +80,13 @@ static int otapreopt_chroot(const int argc, char **arg) {
 
     // Now go on and run otapreopt.
 
-    const char* argv[1 + 9 + 1];
-    CHECK_EQ(argc, 10);
+    const char* argv[1 + DEXOPT_PARAM_COUNT + 1];
+    CHECK_EQ(static_cast<size_t>(argc), DEXOPT_PARAM_COUNT + 1);
     argv[0] = "/system/bin/otapreopt";
-    for (size_t i = 1; i <= 9; ++i) {
+    for (size_t i = 1; i <= DEXOPT_PARAM_COUNT; ++i) {
         argv[i] = arg[i];
     }
-    argv[10] = nullptr;
+    argv[DEXOPT_PARAM_COUNT + 1] = nullptr;
 
     execv(argv[0], (char * const *)argv);
     PLOG(ERROR) << "execv(OTAPREOPT) failed.";
index a31734a..394c244 100644 (file)
 
 # This script will run as a postinstall step to drive otapreopt.
 
+STATUS_FD="$2"
+
 # Maximum number of packages/steps.
 MAXIMUM_PACKAGES=1000
 
 PREPARE=$(cmd otadexopt prepare)
-if [ "$PREPARE" != "Success" ] ; then
-  echo "Failed to prepare."
-  exit 1
-fi
+# Note: Ignore preparation failures. Step and done will fail and exit this.
+#       This is necessary to support suspends - the OTA service will keep
+#       the state around for us.
+
+PROGRESS=$(cmd otadexopt progress)
+print -u${STATUS_FD} "global_progress $PROGRESS"
 
 i=0
 while ((i<MAXIMUM_PACKAGES)) ; do
   cmd otadexopt step
+
+  PROGRESS=$(cmd otadexopt progress)
+  print -u${STATUS_FD} "global_progress $PROGRESS"
+
   DONE=$(cmd otadexopt done)
-  if [ "$DONE" = "OTA complete." ] ; then
-    break
+  if [ "$DONE" = "OTA incomplete." ] ; then
+    sleep 1
+    i=$((i+1))
+    continue
   fi
-  sleep 1
-  i=$((i+1))
+  break
 done
 
 DONE=$(cmd otadexopt done)
@@ -45,6 +54,7 @@ else
   echo "Complete or error."
 fi
 
+print -u${STATUS_FD} "global_progress 1.0"
 cmd otadexopt cleanup
 
 exit 0
diff --git a/cmds/installd/string_helpers.h b/cmds/installd/string_helpers.h
deleted file mode 100644 (file)
index e8fcdef..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015 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 ART_OTAPREOPT_STRING_HELPERS_H_
-#define ART_OTAPREOPT_STRING_HELPERS_H_
-
-#include <sstream>
-#include <string>
-
-#include <android-base/macros.h>
-
-namespace android {
-namespace installd {
-
-static inline bool StringStartsWith(const std::string& target,
-                                    const char* prefix) {
-    return target.compare(0, strlen(prefix), prefix) == 0;
-}
-
-// Split the input according to the separator character. Doesn't honor quotation.
-static inline std::vector<std::string> Split(const std::string& in, const char separator) {
-    if (in.empty()) {
-        return std::vector<std::string>();
-    }
-
-    std::vector<std::string> ret;
-    std::stringstream strstr(in);
-    std::string token;
-
-    while (std::getline(strstr, token, separator)) {
-        ret.push_back(token);
-    }
-
-    return ret;
-}
-
-template <typename StringT>
-static inline std::string Join(const std::vector<StringT>& strings, char separator) {
-    if (strings.empty()) {
-        return "";
-    }
-
-    std::string result(strings[0]);
-    for (size_t i = 1; i < strings.size(); ++i) {
-        result += separator;
-        result += strings[i];
-    }
-    return result;
-}
-
-}  // namespace installd
-}  // namespace android
-
-#endif  // ART_OTAPREOPT_STRING_HELPERS_H_
index 4b7a706..4ff00b5 100644 (file)
@@ -34,7 +34,6 @@
 
     <!-- device administration -->
     <feature name="android.software.device_admin" />
-    <feature name="android.software.managed_users" />
 
     <!-- devices with GPS must include device/google/clockwork/gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
index 67e28da..a17c57a 100644 (file)
@@ -757,7 +757,15 @@ enum {
     /** Copy key. */
     AKEYCODE_COPY = 278,
     /** Paste key. */
-    AKEYCODE_PASTE = 279
+    AKEYCODE_PASTE = 279,
+    /** fingerprint navigation key, up. */
+    AKEYCODE_FP_NAV_UP = 280,
+    /** fingerprint navigation key, down. */
+    AKEYCODE_FP_NAV_DOWN = 281,
+    /** fingerprint navigation key, left. */
+    AKEYCODE_FP_NAV_LEFT = 282,
+    /** fingerprint navigation key, right. */
+    AKEYCODE_FP_NAV_RIGHT = 283
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
index 09300a2..fe4b1fa 100644 (file)
@@ -66,6 +66,8 @@ public:
         virtual void onFrameReplaced(const BufferItem& item) override;
         virtual void onBuffersReleased() override;
         virtual void onSidebandStreamChanged() override;
+        virtual bool getFrameTimestamps(uint64_t frameNumber,
+                FrameTimestamps* outTimestamps) const override;
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
index b2daae4..a9fce1a 100644 (file)
@@ -136,6 +136,10 @@ public:
     // Retrieve the sideband buffer stream, if any.
     virtual sp<NativeHandle> getSidebandStream() const;
 
+    // See IGraphicBufferConsumer::getOccupancyHistory
+    virtual status_t getOccupancyHistory(bool forceFlush,
+            std::vector<OccupancyTracker::Segment>* outHistory) override;
+
     // dump our state in a String
     virtual void dump(String8& result, const char* prefix) const;
 
index 4337da9..6c69d69 100644 (file)
@@ -20,6 +20,7 @@
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueDefs.h>
 #include <gui/BufferSlot.h>
+#include <gui/OccupancyTracker.h>
 
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
@@ -322,6 +323,8 @@ private:
     // The slot of the last queued buffer
     int mLastQueuedSlot;
 
+    OccupancyTracker mOccupancyTracker;
+
 }; // class BufferQueueCore
 
 } // namespace android
index a75ed98..a85bbb7 100644 (file)
@@ -186,6 +186,10 @@ public:
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
 
+    // See IGraphicBufferProducer::getFrameTimestamps
+    virtual bool getFrameTimestamps(uint64_t frameNumber,
+            FrameTimestamps* outTimestamps) const override;
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
index 9307a26..d1f4cdd 100644 (file)
@@ -85,6 +85,10 @@ public:
     // See IGraphicBufferConsumer::setDefaultBufferDataSpace
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
 
+    // See IGraphicBufferConsumer::getOccupancyHistory
+    status_t getOccupancyHistory(bool forceFlush,
+            std::vector<OccupancyTracker::Segment>* outHistory);
+
 private:
     ConsumerBase(const ConsumerBase&);
     void operator=(const ConsumerBase&);
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
new file mode 100644 (file)
index 0000000..4dc7467
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 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 ANDROID_GUI_FRAMETIMESTAMPS_H
+#define ANDROID_GUI_FRAMETIMESTAMPS_H
+
+#include <utils/Timers.h>
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
+    FrameTimestamps() :
+        frameNumber(0),
+        postedTime(0),
+        acquireTime(0),
+        refreshStartTime(0),
+        glCompositionDoneTime(0),
+        displayRetireTime(0),
+        releaseTime(0) {}
+
+    uint64_t frameNumber;
+    nsecs_t postedTime;
+    nsecs_t acquireTime;
+    nsecs_t refreshStartTime;
+    nsecs_t glCompositionDoneTime;
+    nsecs_t displayRetireTime;
+    nsecs_t releaseTime;
+};
+
+} // namespace android
+#endif
index 3f39799..1efcf3c 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <binder/IInterface.h>
 
+#include <gui/FrameTimestamps.h>
+
 namespace android {
 // ----------------------------------------------------------------------------
 
@@ -78,6 +80,11 @@ public:
     // stream is first attached and when it is either detached or replaced by a
     // different stream.
     virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
+
+    // See IGraphicBufferProducer::getFrameTimestamps
+    // This queries the consumer for the timestamps
+    virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
+            FrameTimestamps* /*outTimestamps*/) const { return false; }
 };
 
 
index e983c16..4915478 100644 (file)
@@ -27,6 +27,7 @@
 #include <binder/IInterface.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
+#include <gui/OccupancyTracker.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -265,6 +266,12 @@ public:
     // Retrieve the sideband buffer stream, if any.
     virtual sp<NativeHandle> getSidebandStream() const = 0;
 
+    // Retrieves any stored segments of the occupancy history of this
+    // BufferQueue and clears them. Optionally closes out the pending segment if
+    // forceFlush is true.
+    virtual status_t getOccupancyHistory(bool forceFlush,
+            std::vector<OccupancyTracker::Segment>* outHistory) = 0;
+
     // dump state into a string
     virtual void dump(String8& result, const char* prefix) const = 0;
 
index 37ae6df..0c24606 100644 (file)
@@ -30,6 +30,8 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
+#include <gui/FrameTimestamps.h>
+
 namespace android {
 // ----------------------------------------------------------------------------
 
@@ -568,6 +570,14 @@ public:
     // Returns NO_ERROR or the status of the Binder transaction
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) = 0;
+
+    // Attempts to retrieve timestamp information for the given frame number.
+    // If information for the given frame number is not found, returns false.
+    // Returns true otherwise.
+    //
+    // If a fence has not yet signaled the timestamp returned will be 0;
+    virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
+            FrameTimestamps* /*outTimestamps*/) const { return false; }
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/OccupancyTracker.h b/include/gui/OccupancyTracker.h
new file mode 100644 (file)
index 0000000..1d15e7f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 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 ANDROID_GUI_OCCUPANCYTRACKER_H
+#define ANDROID_GUI_OCCUPANCYTRACKER_H
+
+#include <binder/Parcelable.h>
+
+#include <utils/Timers.h>
+
+#include <deque>
+#include <unordered_map>
+
+namespace android {
+
+class String8;
+
+class OccupancyTracker
+{
+public:
+    OccupancyTracker()
+      : mPendingSegment(),
+        mSegmentHistory(),
+        mLastOccupancy(0),
+        mLastOccupancyChangeTime(0) {}
+
+    struct Segment : public Parcelable {
+        Segment()
+          : totalTime(0),
+            numFrames(0),
+            occupancyAverage(0.0f),
+            usedThirdBuffer(false) {}
+
+        Segment(nsecs_t totalTime, size_t numFrames, float occupancyAverage,
+                bool usedThirdBuffer)
+          : totalTime(totalTime),
+            numFrames(numFrames),
+            occupancyAverage(occupancyAverage),
+            usedThirdBuffer(usedThirdBuffer) {}
+
+        // Parcelable interface
+        virtual status_t writeToParcel(Parcel* parcel) const override;
+        virtual status_t readFromParcel(const Parcel* parcel) override;
+
+        nsecs_t totalTime;
+        size_t numFrames;
+
+        // Average occupancy of the queue over this segment. (0.0, 1.0) implies
+        // double-buffered, (1.0, 2.0) implies triple-buffered.
+        float occupancyAverage;
+
+        // Whether a third buffer was used at all during this segment (since a
+        // segment could read as double-buffered on average, but still require a
+        // third buffer to avoid jank for some smaller portion)
+        bool usedThirdBuffer;
+    };
+
+    void registerOccupancyChange(size_t occupancy);
+    std::vector<Segment> getSegmentHistory(bool forceFlush);
+
+private:
+    static constexpr size_t MAX_HISTORY_SIZE = 10;
+    static constexpr nsecs_t NEW_SEGMENT_DELAY = ms2ns(100);
+    static constexpr size_t LONG_SEGMENT_THRESHOLD = 3;
+
+    struct PendingSegment {
+        void clear() {
+            totalTime = 0;
+            numFrames = 0;
+            mOccupancyTimes.clear();
+        }
+
+        nsecs_t totalTime;
+        size_t numFrames;
+        std::unordered_map<size_t, nsecs_t> mOccupancyTimes;
+    };
+
+    void recordPendingSegment();
+
+    PendingSegment mPendingSegment;
+    std::deque<Segment> mSegmentHistory;
+
+    size_t mLastOccupancy;
+    nsecs_t mLastOccupancyChangeTime;
+
+}; // class OccupancyTracker
+
+} // namespace android
+
+#endif
index 646203b..7d9d901 100644 (file)
@@ -134,6 +134,12 @@ public:
     status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]);
 
+    // See IGraphicBufferProducer::getFrameTimestamps
+    bool getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
+            nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
+            nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+            nsecs_t* outReleaseTime);
+
 protected:
     virtual ~Surface();
 
@@ -183,6 +189,7 @@ private:
     int dispatchSetSurfaceDamage(va_list args);
     int dispatchSetSharedBufferMode(va_list args);
     int dispatchSetAutoRefresh(va_list args);
+    int dispatchGetFrameTimestamps(va_list args);
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
index b7012eb..542f647 100644 (file)
@@ -319,6 +319,10 @@ static const InputEventLabel KEYCODES[] = {
     DEFINE_KEYCODE(CUT),
     DEFINE_KEYCODE(COPY),
     DEFINE_KEYCODE(PASTE),
+    DEFINE_KEYCODE(FP_NAV_UP),
+    DEFINE_KEYCODE(FP_NAV_DOWN),
+    DEFINE_KEYCODE(FP_NAV_LEFT),
+    DEFINE_KEYCODE(FP_NAV_RIGHT),
 
     { NULL, 0 }
 };
diff --git a/include/ui/Gralloc1.h b/include/ui/Gralloc1.h
new file mode 100644 (file)
index 0000000..cf8c173
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2016 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 ANDROID_UI_GRALLOC1_H
+#define ANDROID_UI_GRALLOC1_H
+
+#define GRALLOC1_LOG_TAG "Gralloc1"
+
+#include <ui/Gralloc1On0Adapter.h>
+
+#include <unordered_set>
+
+namespace std {
+    template <>
+    struct hash<gralloc1_capability_t> {
+        size_t operator()(gralloc1_capability_t capability) const {
+            return std::hash<int32_t>()(static_cast<int32_t>(capability));
+        }
+    };
+}
+
+namespace android {
+
+class Fence;
+class GraphicBuffer;
+
+namespace Gralloc1 {
+
+class Device;
+
+class Descriptor {
+public:
+    Descriptor(Device& device, gralloc1_buffer_descriptor_t deviceId)
+      : mShimDevice(device),
+        mDeviceId(deviceId),
+        mWidth(0),
+        mHeight(0),
+        mFormat(static_cast<android_pixel_format_t>(0)),
+        mProducerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+        mConsumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+    ~Descriptor();
+
+    gralloc1_buffer_descriptor_t getDeviceId() const { return mDeviceId; }
+
+    gralloc1_error_t setDimensions(uint32_t width, uint32_t height);
+    gralloc1_error_t setFormat(android_pixel_format_t format);
+    gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage);
+    gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage);
+
+private:
+    Device& mShimDevice;
+    const gralloc1_buffer_descriptor_t mDeviceId;
+
+    uint32_t mWidth;
+    uint32_t mHeight;
+    android_pixel_format_t mFormat;
+    gralloc1_producer_usage_t mProducerUsage;
+    gralloc1_consumer_usage_t mConsumerUsage;
+
+}; // Descriptor
+
+class Device {
+    friend class Gralloc1::Descriptor;
+
+public:
+    Device(gralloc1_device_t* device);
+
+    bool hasCapability(gralloc1_capability_t capability) const;
+
+    std::string dump();
+
+    std::shared_ptr<Descriptor> createDescriptor();
+
+    gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
+
+    gralloc1_error_t allocate(
+            const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+            std::vector<buffer_handle_t>* outBuffers);
+    gralloc1_error_t allocate(
+            const std::shared_ptr<const Descriptor>& descriptor,
+            gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+
+    gralloc1_error_t retain(buffer_handle_t buffer);
+    gralloc1_error_t retain(const GraphicBuffer* buffer);
+
+    gralloc1_error_t release(buffer_handle_t buffer);
+
+    gralloc1_error_t getNumFlexPlanes(buffer_handle_t buffer,
+            uint32_t* outNumPlanes);
+
+    gralloc1_error_t lock(buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion, void** outData,
+            const sp<Fence>& acquireFence);
+    gralloc1_error_t lockFlex(buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion,
+            struct android_flex_layout* outData, const sp<Fence>& acquireFence);
+    gralloc1_error_t lockYCbCr(buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion, struct android_ycbcr* outData,
+            const sp<Fence>& acquireFence);
+
+    gralloc1_error_t unlock(buffer_handle_t buffer, sp<Fence>* outFence);
+
+private:
+    std::unordered_set<gralloc1_capability_t> loadCapabilities();
+
+    bool loadFunctions();
+
+    template <typename LockType, typename OutType>
+    gralloc1_error_t lockHelper(LockType pfn, buffer_handle_t buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t* accessRegion, OutType* outData,
+            const sp<Fence>& acquireFence) {
+        int32_t intError = pfn(mDevice, buffer,
+                static_cast<uint64_t>(producerUsage),
+                static_cast<uint64_t>(consumerUsage), accessRegion, outData,
+                acquireFence->dup());
+        return static_cast<gralloc1_error_t>(intError);
+    }
+
+    gralloc1_device_t* const mDevice;
+
+    const std::unordered_set<gralloc1_capability_t> mCapabilities;
+
+    template <typename PFN, gralloc1_function_descriptor_t descriptor>
+    struct FunctionLoader {
+        FunctionLoader() : pfn(nullptr) {}
+
+        bool load(gralloc1_device_t* device, bool errorIfNull) {
+            gralloc1_function_pointer_t rawPointer =
+                    device->getFunction(device, descriptor);
+            pfn = reinterpret_cast<PFN>(rawPointer);
+            if (errorIfNull && !rawPointer) {
+                ALOG(LOG_ERROR, GRALLOC1_LOG_TAG,
+                        "Failed to load function pointer %d", descriptor);
+            }
+            return rawPointer != nullptr;
+        }
+
+        template <typename ...Args>
+        typename std::result_of<PFN(Args...)>::type operator()(Args... args) {
+            return pfn(args...);
+        }
+
+        PFN pfn;
+    };
+
+    // Function pointers
+    struct Functions {
+        FunctionLoader<GRALLOC1_PFN_DUMP, GRALLOC1_FUNCTION_DUMP> dump;
+        FunctionLoader<GRALLOC1_PFN_CREATE_DESCRIPTOR,
+                GRALLOC1_FUNCTION_CREATE_DESCRIPTOR> createDescriptor;
+        FunctionLoader<GRALLOC1_PFN_DESTROY_DESCRIPTOR,
+                GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR> destroyDescriptor;
+        FunctionLoader<GRALLOC1_PFN_SET_CONSUMER_USAGE,
+                GRALLOC1_FUNCTION_SET_CONSUMER_USAGE> setConsumerUsage;
+        FunctionLoader<GRALLOC1_PFN_SET_DIMENSIONS,
+                GRALLOC1_FUNCTION_SET_DIMENSIONS> setDimensions;
+        FunctionLoader<GRALLOC1_PFN_SET_FORMAT,
+                GRALLOC1_FUNCTION_SET_FORMAT> setFormat;
+        FunctionLoader<GRALLOC1_PFN_SET_PRODUCER_USAGE,
+                GRALLOC1_FUNCTION_SET_PRODUCER_USAGE> setProducerUsage;
+        FunctionLoader<GRALLOC1_PFN_GET_BACKING_STORE,
+                GRALLOC1_FUNCTION_GET_BACKING_STORE> getBackingStore;
+        FunctionLoader<GRALLOC1_PFN_GET_CONSUMER_USAGE,
+                GRALLOC1_FUNCTION_GET_CONSUMER_USAGE> getConsumerUsage;
+        FunctionLoader<GRALLOC1_PFN_GET_DIMENSIONS,
+                GRALLOC1_FUNCTION_GET_DIMENSIONS> getDimensions;
+        FunctionLoader<GRALLOC1_PFN_GET_FORMAT,
+                GRALLOC1_FUNCTION_GET_FORMAT> getFormat;
+        FunctionLoader<GRALLOC1_PFN_GET_PRODUCER_USAGE,
+                GRALLOC1_FUNCTION_GET_PRODUCER_USAGE> getProducerUsage;
+        FunctionLoader<GRALLOC1_PFN_GET_STRIDE,
+                GRALLOC1_FUNCTION_GET_STRIDE> getStride;
+        FunctionLoader<GRALLOC1_PFN_ALLOCATE,
+                GRALLOC1_FUNCTION_ALLOCATE> allocate;
+        FunctionLoader<GRALLOC1_PFN_RETAIN,
+                GRALLOC1_FUNCTION_RETAIN> retain;
+        FunctionLoader<GRALLOC1_PFN_RELEASE,
+                GRALLOC1_FUNCTION_RELEASE> release;
+        FunctionLoader<GRALLOC1_PFN_GET_NUM_FLEX_PLANES,
+                GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES> getNumFlexPlanes;
+        FunctionLoader<GRALLOC1_PFN_LOCK,
+                GRALLOC1_FUNCTION_LOCK> lock;
+        FunctionLoader<GRALLOC1_PFN_LOCK_FLEX,
+                GRALLOC1_FUNCTION_LOCK_FLEX> lockFlex;
+        FunctionLoader<GRALLOC1_PFN_LOCK_YCBCR,
+                GRALLOC1_FUNCTION_LOCK_YCBCR> lockYCbCr;
+        FunctionLoader<GRALLOC1_PFN_UNLOCK,
+                GRALLOC1_FUNCTION_UNLOCK> unlock;
+
+        // Adapter-only functions
+        FunctionLoader<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER,
+                GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER> retainGraphicBuffer;
+        FunctionLoader<GRALLOC1_PFN_ALLOCATE_WITH_ID,
+                GRALLOC1_FUNCTION_ALLOCATE_WITH_ID> allocateWithId;
+    } mFunctions;
+
+}; // class android::Gralloc1::Device
+
+class Loader
+{
+public:
+    Loader();
+    ~Loader();
+
+    std::unique_ptr<Device> getDevice();
+
+private:
+    static std::unique_ptr<Gralloc1On0Adapter> mAdapter;
+    std::unique_ptr<Device> mDevice;
+};
+
+} // namespace android::Gralloc1
+
+} // namespace android
+
+#endif
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
new file mode 100644 (file)
index 0000000..edcfb65
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2016 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 ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
+#define ANDROID_UI_GRALLOC_1_ON_0_ADAPTER_H
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <hardware/gralloc1.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+struct gralloc_module_t;
+
+// This is not an "official" capability (i.e., it is not found in gralloc1.h),
+// but we will use it to detect that we are running through the adapter, which
+// is capable of collaborating with GraphicBuffer such that queries on a
+// buffer_handle_t succeed
+static const auto GRALLOC1_CAPABILITY_ON_ADAPTER =
+        static_cast<gralloc1_capability_t>(GRALLOC1_LAST_CAPABILITY + 1);
+
+static const auto GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER =
+        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 1);
+static const auto GRALLOC1_FUNCTION_ALLOCATE_WITH_ID =
+        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 2);
+static const auto GRALLOC1_FUNCTION_LOCK_YCBCR =
+        static_cast<gralloc1_function_descriptor_t>(GRALLOC1_LAST_FUNCTION + 3);
+static const auto GRALLOC1_LAST_ADAPTER_FUNCTION = GRALLOC1_FUNCTION_LOCK_YCBCR;
+
+typedef gralloc1_error_t (*GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER)(
+        gralloc1_device_t* device, const android::GraphicBuffer* buffer);
+typedef gralloc1_error_t (*GRALLOC1_PFN_ALLOCATE_WITH_ID)(
+        gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptor,
+        gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+typedef int32_t /*gralloc1_error_t*/ (*GRALLOC1_PFN_LOCK_YCBCR)(
+        gralloc1_device_t* device, buffer_handle_t buffer,
+        uint64_t /*gralloc1_producer_usage_t*/ producerUsage,
+        uint64_t /*gralloc1_consumer_usage_t*/ consumerUsage,
+        const gralloc1_rect_t* accessRegion, struct android_ycbcr* outYCbCr,
+        int32_t acquireFence);
+
+namespace android {
+
+class Gralloc1On0Adapter : public gralloc1_device_t
+{
+public:
+    Gralloc1On0Adapter(const hw_module_t* module);
+    ~Gralloc1On0Adapter();
+
+    gralloc1_device_t* getDevice() {
+        return static_cast<gralloc1_device_t*>(this);
+    }
+
+private:
+    static inline Gralloc1On0Adapter* getAdapter(gralloc1_device_t* device) {
+        return static_cast<Gralloc1On0Adapter*>(device);
+    }
+
+    // getCapabilities
+
+    void doGetCapabilities(uint32_t* outCount,
+            int32_t* /*gralloc1_capability_t*/ outCapabilities);
+    static void getCapabilitiesHook(gralloc1_device_t* device,
+            uint32_t* outCount,
+            int32_t* /*gralloc1_capability_t*/ outCapabilities) {
+        getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
+    };
+
+    // getFunction
+
+    gralloc1_function_pointer_t doGetFunction(
+            int32_t /*gralloc1_function_descriptor_t*/ descriptor);
+    static gralloc1_function_pointer_t getFunctionHook(
+            gralloc1_device_t* device,
+            int32_t /*gralloc1_function_descriptor_t*/ descriptor) {
+        return getAdapter(device)->doGetFunction(descriptor);
+    }
+
+    // dump
+
+    void dump(uint32_t* outSize, char* outBuffer);
+    static void dumpHook(gralloc1_device_t* device, uint32_t* outSize,
+            char* outBuffer) {
+        return getAdapter(device)->dump(outSize, outBuffer);
+    }
+    std::string mCachedDump;
+
+    // Buffer descriptor lifecycle functions
+
+    class Descriptor;
+
+    gralloc1_error_t createDescriptor(
+            gralloc1_buffer_descriptor_t* outDescriptor);
+    static int32_t createDescriptorHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t* outDescriptor) {
+        auto error = getAdapter(device)->createDescriptor(outDescriptor);
+        return static_cast<int32_t>(error);
+    }
+
+    gralloc1_error_t destroyDescriptor(gralloc1_buffer_descriptor_t descriptor);
+    static int32_t destroyDescriptorHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptor) {
+        auto error = getAdapter(device)->destroyDescriptor(descriptor);
+        return static_cast<int32_t>(error);
+    }
+
+    // Buffer descriptor modification functions
+
+    struct Descriptor : public std::enable_shared_from_this<Descriptor> {
+        Descriptor(Gralloc1On0Adapter* adapter,
+                gralloc1_buffer_descriptor_t id)
+          : adapter(adapter),
+            id(id),
+            width(0),
+            height(0),
+            format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+            producerUsage(GRALLOC1_PRODUCER_USAGE_NONE),
+            consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {}
+
+        gralloc1_error_t setDimensions(uint32_t w, uint32_t h) {
+            width = w;
+            height = h;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t setFormat(int32_t f) {
+            format = f;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) {
+            producerUsage = usage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage) {
+            consumerUsage = usage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        Gralloc1On0Adapter* const adapter;
+        const gralloc1_buffer_descriptor_t id;
+
+        uint32_t width;
+        uint32_t height;
+        int32_t format;
+        gralloc1_producer_usage_t producerUsage;
+        gralloc1_consumer_usage_t consumerUsage;
+    };
+
+    template <typename ...Args>
+    static int32_t callDescriptorFunction(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId,
+            gralloc1_error_t (Descriptor::*member)(Args...), Args... args) {
+        auto descriptor = getAdapter(device)->getDescriptor(descriptorId);
+        if (!descriptor) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_DESCRIPTOR);
+        }
+        auto error = ((*descriptor).*member)(std::forward<Args>(args)...);
+        return static_cast<int32_t>(error);
+    }
+
+    static int32_t setConsumerUsageHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+        auto usage = static_cast<gralloc1_consumer_usage_t>(intUsage);
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setConsumerUsage, usage);
+    }
+
+    static int32_t setDimensionsHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, uint32_t width,
+            uint32_t height) {
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setDimensions, width, height);
+    }
+
+    static int32_t setFormatHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, int32_t format) {
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setFormat, format);
+    }
+
+    static int32_t setProducerUsageHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) {
+        auto usage = static_cast<gralloc1_producer_usage_t>(intUsage);
+        return callDescriptorFunction(device, descriptorId,
+                &Descriptor::setProducerUsage, usage);
+    }
+
+    // Buffer handle query functions
+
+    class Buffer {
+    public:
+        Buffer(buffer_handle_t handle, gralloc1_backing_store_t store,
+                const Descriptor& descriptor, uint32_t stride,
+                bool wasAllocated);
+
+        buffer_handle_t getHandle() const { return mHandle; }
+
+        void retain() { ++mReferenceCount; }
+
+        // Returns true if the reference count has dropped to 0, indicating that
+        // the buffer needs to be released
+        bool release() { return --mReferenceCount == 0; }
+
+        bool wasAllocated() const { return mWasAllocated; }
+
+        gralloc1_error_t getBackingStore(
+                gralloc1_backing_store_t* outStore) const {
+            *outStore = mStore;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getConsumerUsage(
+                gralloc1_consumer_usage_t* outUsage) const {
+            *outUsage = mDescriptor.consumerUsage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getDimensions(uint32_t* outWidth,
+                uint32_t* outHeight) const {
+            *outWidth = mDescriptor.width;
+            *outHeight = mDescriptor.height;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getFormat(int32_t* outFormat) const {
+            *outFormat = mDescriptor.format;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const {
+            // TODO: This is conservative, and we could do better by examining
+            // the format, but it won't hurt anything for now
+            *outNumPlanes = 4;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getProducerUsage(
+                gralloc1_producer_usage_t* outUsage) const {
+            *outUsage = mDescriptor.producerUsage;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+        gralloc1_error_t getStride(uint32_t* outStride) const {
+            *outStride = mStride;
+            return GRALLOC1_ERROR_NONE;
+        }
+
+    private:
+
+        const buffer_handle_t mHandle;
+        size_t mReferenceCount;
+
+        // Since we're adapting to gralloc0, there will always be a 1:1
+        // correspondence between buffer handles and backing stores, and the
+        // backing store ID will be the same as the GraphicBuffer unique ID
+        const gralloc1_backing_store_t mStore;
+
+        const Descriptor mDescriptor;
+        const uint32_t mStride;
+
+        // Whether this buffer allocated in this process (as opposed to just
+        // being retained here), which determines whether to free or unregister
+        // the buffer when this Buffer is released
+        const bool mWasAllocated;
+    };
+
+    template <typename ...Args>
+    static int32_t callBufferFunction(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle,
+            gralloc1_error_t (Buffer::*member)(Args...) const, Args... args) {
+        auto buffer = getAdapter(device)->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+        auto error = ((*buffer).*member)(std::forward<Args>(args)...);
+        return static_cast<int32_t>(error);
+    }
+
+    template <typename MF, MF memFunc, typename ...Args>
+    static int32_t bufferHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, Args... args) {
+        return Gralloc1On0Adapter::callBufferFunction(device, bufferHandle,
+                memFunc, std::forward<Args>(args)...);
+    }
+
+    static int32_t getConsumerUsageHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, uint64_t* outUsage) {
+        auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
+        auto error = callBufferFunction(device, bufferHandle,
+                &Buffer::getConsumerUsage, &usage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            *outUsage = static_cast<uint64_t>(usage);
+        }
+        return error;
+    }
+
+    static int32_t getProducerUsageHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, uint64_t* outUsage) {
+        auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
+        auto error = callBufferFunction(device, bufferHandle,
+                &Buffer::getProducerUsage, &usage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            *outUsage = static_cast<uint64_t>(usage);
+        }
+        return error;
+    }
+
+    // Buffer management functions
+
+    // We don't provide GRALLOC1_FUNCTION_ALLOCATE, since this should always be
+    // called through GRALLOC1_FUNCTION_ALLOCATE_WITH_ID
+    gralloc1_error_t allocate(
+            const std::shared_ptr<Descriptor>& descriptor,
+            gralloc1_backing_store_t id,
+            buffer_handle_t* outBufferHandle);
+    static gralloc1_error_t allocateWithIdHook(gralloc1_device_t* device,
+            gralloc1_buffer_descriptor_t descriptors,
+            gralloc1_backing_store_t id, buffer_handle_t* outBuffer);
+
+    gralloc1_error_t retain(const std::shared_ptr<Buffer>& buffer);
+    gralloc1_error_t release(const std::shared_ptr<Buffer>& buffer);
+
+    // Member function pointer 'member' will either be retain or release
+    template <gralloc1_error_t (Gralloc1On0Adapter::*member)(
+            const std::shared_ptr<Buffer>& buffer)>
+    static int32_t managementHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle) {
+        auto adapter = getAdapter(device);
+
+        auto buffer = adapter->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+
+        auto error = ((*adapter).*member)(buffer);
+        return static_cast<int32_t>(error);
+    }
+
+    gralloc1_error_t retain(const GraphicBuffer* buffer);
+    static gralloc1_error_t retainGraphicBufferHook(gralloc1_device_t* device,
+            const GraphicBuffer* buffer) {
+        auto adapter = getAdapter(device);
+        return adapter->retain(buffer);
+    }
+
+    // Buffer access functions
+
+    gralloc1_error_t lock(const std::shared_ptr<Buffer>& buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t& accessRegion, void** outData,
+            const sp<Fence>& acquireFence);
+    gralloc1_error_t lockFlex(const std::shared_ptr<Buffer>& buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t& accessRegion,
+            struct android_flex_layout* outFlex,
+            const sp<Fence>& acquireFence);
+    gralloc1_error_t lockYCbCr(const std::shared_ptr<Buffer>& buffer,
+            gralloc1_producer_usage_t producerUsage,
+            gralloc1_consumer_usage_t consumerUsage,
+            const gralloc1_rect_t& accessRegion,
+            struct android_ycbcr* outFlex,
+            const sp<Fence>& acquireFence);
+
+    template <typename OUT, gralloc1_error_t (Gralloc1On0Adapter::*member)(
+            const std::shared_ptr<Buffer>&, gralloc1_producer_usage_t,
+            gralloc1_consumer_usage_t, const gralloc1_rect_t&, OUT*,
+            const sp<Fence>&)>
+    static int32_t lockHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle,
+            uint64_t /*gralloc1_producer_usage_t*/ uintProducerUsage,
+            uint64_t /*gralloc1_consumer_usage_t*/ uintConsumerUsage,
+            const gralloc1_rect_t* accessRegion, OUT* outData,
+            int32_t acquireFenceFd) {
+        auto adapter = getAdapter(device);
+
+        // Exactly one of producer and consumer usage must be *_USAGE_NONE,
+        // but we can't check this until the upper levels of the framework
+        // correctly distinguish between producer and consumer usage
+        /*
+        bool hasProducerUsage =
+                uintProducerUsage != GRALLOC1_PRODUCER_USAGE_NONE;
+        bool hasConsumerUsage =
+                uintConsumerUsage != GRALLOC1_CONSUMER_USAGE_NONE;
+        if (hasProducerUsage && hasConsumerUsage ||
+                !hasProducerUsage && !hasConsumerUsage) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+        }
+        */
+
+        auto producerUsage =
+                static_cast<gralloc1_producer_usage_t>(uintProducerUsage);
+        auto consumerUsage =
+                static_cast<gralloc1_consumer_usage_t>(uintConsumerUsage);
+
+        if (!outData) {
+            const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ |
+                    GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+            if (producerUsage & producerCpuUsage != 0) {
+                return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+            }
+            if (consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ != 0) {
+                return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+            }
+        }
+
+        auto buffer = adapter->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+
+        if (!accessRegion) {
+            ALOGE("accessRegion is null");
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
+        }
+
+        sp<Fence> acquireFence{new Fence(acquireFenceFd)};
+        auto error = ((*adapter).*member)(buffer, producerUsage, consumerUsage,
+                *accessRegion, outData, acquireFence);
+        return static_cast<int32_t>(error);
+    }
+
+    gralloc1_error_t unlock(const std::shared_ptr<Buffer>& buffer,
+            sp<Fence>* outReleaseFence);
+    static int32_t unlockHook(gralloc1_device_t* device,
+            buffer_handle_t bufferHandle, int32_t* outReleaseFenceFd) {
+        auto adapter = getAdapter(device);
+
+        auto buffer = adapter->getBuffer(bufferHandle);
+        if (!buffer) {
+            return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE);
+        }
+
+        sp<Fence> releaseFence = Fence::NO_FENCE;
+        auto error = adapter->unlock(buffer, &releaseFence);
+        if (error == GRALLOC1_ERROR_NONE) {
+            *outReleaseFenceFd = releaseFence->dup();
+        }
+        return static_cast<int32_t>(error);
+    }
+
+    // Adapter internals
+    const gralloc_module_t* mModule;
+    uint8_t mMinorVersion;
+    alloc_device_t* mDevice;
+
+    std::shared_ptr<Descriptor> getDescriptor(
+            gralloc1_buffer_descriptor_t descriptorId);
+    std::shared_ptr<Buffer> getBuffer(buffer_handle_t bufferHandle);
+
+    static std::atomic<gralloc1_buffer_descriptor_t> sNextBufferDescriptorId;
+    std::unordered_map<gralloc1_buffer_descriptor_t,
+            std::shared_ptr<Descriptor>> mDescriptors;
+    std::unordered_map<buffer_handle_t, std::shared_ptr<Buffer>> mBuffers;
+};
+
+} // namespace android
+
+#endif
index 5443f09..62ebbd5 100644 (file)
 #include <utils/threads.h>
 #include <utils/Singleton.h>
 
+#include <ui/Gralloc1.h>
 #include <ui/PixelFormat.h>
 
-#include <hardware/gralloc.h>
-
-
 namespace android {
-// ---------------------------------------------------------------------------
 
+class Gralloc1Loader;
 class String8;
 
 class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
 {
 public:
     enum {
-        USAGE_SW_READ_NEVER     = GRALLOC_USAGE_SW_READ_NEVER,
-        USAGE_SW_READ_RARELY    = GRALLOC_USAGE_SW_READ_RARELY,
-        USAGE_SW_READ_OFTEN     = GRALLOC_USAGE_SW_READ_OFTEN,
-        USAGE_SW_READ_MASK      = GRALLOC_USAGE_SW_READ_MASK,
+        USAGE_SW_READ_NEVER     = GRALLOC1_CONSUMER_USAGE_CPU_READ_NEVER,
+        USAGE_SW_READ_RARELY    = GRALLOC1_CONSUMER_USAGE_CPU_READ,
+        USAGE_SW_READ_OFTEN     = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
+        USAGE_SW_READ_MASK      = GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN,
 
-        USAGE_SW_WRITE_NEVER    = GRALLOC_USAGE_SW_WRITE_NEVER,
-        USAGE_SW_WRITE_RARELY   = GRALLOC_USAGE_SW_WRITE_RARELY,
-        USAGE_SW_WRITE_OFTEN    = GRALLOC_USAGE_SW_WRITE_OFTEN,
-        USAGE_SW_WRITE_MASK     = GRALLOC_USAGE_SW_WRITE_MASK,
+        USAGE_SW_WRITE_NEVER    = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_NEVER,
+        USAGE_SW_WRITE_RARELY   = GRALLOC1_PRODUCER_USAGE_CPU_WRITE,
+        USAGE_SW_WRITE_OFTEN    = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
+        USAGE_SW_WRITE_MASK     = GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
 
         USAGE_SOFTWARE_MASK     = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
 
-        USAGE_HW_TEXTURE        = GRALLOC_USAGE_HW_TEXTURE,
-        USAGE_HW_RENDER         = GRALLOC_USAGE_HW_RENDER,
-        USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
-        USAGE_HW_MASK           = GRALLOC_USAGE_HW_MASK
+        USAGE_HW_TEXTURE        = GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE,
+        USAGE_HW_RENDER         = GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET,
+        USAGE_HW_2D             = 0x00000400, // Deprecated
+        USAGE_HW_MASK           = 0x00071F00, // Deprecated
     };
 
     static inline GraphicBufferAllocator& get() { return getInstance(); }
 
-    status_t alloc(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
-            buffer_handle_t* handle, uint32_t* stride);
+    status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
+            uint32_t usage, buffer_handle_t* handle, uint32_t* stride,
+            uint64_t graphicBufferId);
 
     status_t free(buffer_handle_t handle);
 
@@ -86,7 +85,8 @@ private:
     GraphicBufferAllocator();
     ~GraphicBufferAllocator();
 
-    alloc_device_t  *mAllocDev;
+    std::unique_ptr<Gralloc1::Loader> mLoader;
+    std::unique_ptr<Gralloc1::Device> mDevice;
 };
 
 // ---------------------------------------------------------------------------
index 6099548..a25809c 100644 (file)
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Singleton.h>
-
-#include <hardware/gralloc.h>
+#include <ui/Gralloc1.h>
 
-
-struct gralloc_module_t;
+#include <utils/Singleton.h>
 
 namespace android {
 
@@ -39,6 +36,7 @@ public:
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
     status_t registerBuffer(buffer_handle_t handle);
+    status_t registerBuffer(const GraphicBuffer* buffer);
 
     status_t unregisterBuffer(buffer_handle_t handle);
 
@@ -59,13 +57,13 @@ public:
 
     status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
 
-    // dumps information about the mapping of this handle
-    void dump(buffer_handle_t handle);
-
 private:
     friend class Singleton<GraphicBufferMapper>;
+
     GraphicBufferMapper();
-    gralloc_module_t const *mAllocMod;
+
+    std::unique_ptr<Gralloc1::Loader> mLoader;
+    std::unique_ptr<Gralloc1::Device> mDevice;
 };
 
 // ---------------------------------------------------------------------------
index 635020e..46feb1c 100644 (file)
@@ -64,6 +64,7 @@ LOCAL_SRC_FILES := \
        ISurfaceComposer.cpp \
        ISurfaceComposerClient.cpp \
        LayerState.cpp \
+       OccupancyTracker.cpp \
        Sensor.cpp \
        SensorEventQueue.cpp \
        SensorManager.cpp \
index ccbb5a2..6de98f5 100644 (file)
@@ -61,6 +61,15 @@ void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
     }
 }
 
+bool BufferQueue::ProxyConsumerListener::getFrameTimestamps(
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        return listener->getFrameTimestamps(frameNumber, outTimestamps);
+    }
+    return false;
+}
+
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
         sp<IGraphicBufferConsumer>* outConsumer,
         const sp<IGraphicBufferAlloc>& allocator) {
index cbc8893..e8860d1 100644 (file)
@@ -260,6 +260,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
         mCore->mDequeueCondition.broadcast();
 
         ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+        mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
 
         VALIDATE_CONSISTENCY();
     }
@@ -717,6 +718,13 @@ sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
     return mCore->mSidebandStream;
 }
 
+status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush,
+        std::vector<OccupancyTracker::Segment>* outHistory) {
+    Mutex::Autolock lock(mCore->mMutex);
+    *outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush);
+    return NO_ERROR;
+}
+
 void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
     const IPCThreadState* ipc = IPCThreadState::self();
     const pid_t pid = ipc->getCallingPid();
index 69a408c..3a0a283 100644 (file)
@@ -890,6 +890,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
                 static_cast<uint32_t>(mCore->mQueue.size()));
 
         ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+        mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
 
         // Take a ticket for the callback functions
         callbackTicket = mNextCallbackTicket++;
@@ -1404,6 +1405,22 @@ status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
     return NO_ERROR;
 }
 
+bool BufferQueueProducer::getFrameTimestamps(uint64_t frameNumber,
+        FrameTimestamps* outTimestamps) const {
+    ATRACE_CALL();
+    BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
+    sp<IConsumerListener> listener;
+
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+        listener = mCore->mConsumerListener;
+    }
+    if (listener != NULL) {
+        return listener->getFrameTimestamps(frameNumber, outTimestamps);
+    }
+    return false;
+}
+
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
     // If we're here, it means that a producer we were connected to died.
     // We're guaranteed that we are still connected to it because we remove
index a6a9712..84965ef 100644 (file)
@@ -235,6 +235,16 @@ status_t ConsumerBase::setDefaultBufferDataSpace(
     return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
 }
 
+status_t ConsumerBase::getOccupancyHistory(bool forceFlush,
+        std::vector<OccupancyTracker::Segment>* outHistory) {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("getOccupancyHistory: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->getOccupancyHistory(forceFlush, outHistory);
+}
+
 void ConsumerBase::dump(String8& result) const {
     dump(result, "");
 }
index cab7dc3..9a06011 100644 (file)
@@ -31,6 +31,7 @@ enum {
     ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
     ON_BUFFER_RELEASED,
     ON_SIDEBAND_STREAM_CHANGED,
+    GET_FRAME_TIMESTAMPS
 };
 
 class BpConsumerListener : public BpInterface<IConsumerListener>
@@ -60,6 +61,42 @@ public:
         data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
         remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual bool getFrameTimestamps(uint64_t frameNumber,
+            FrameTimestamps* outTimestamps) const {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(
+                IConsumerListener::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to write token: %d", result);
+            return false;
+        }
+        result = data.writeUint64(frameNumber);
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to write: %d", result);
+            return false;
+        }
+        result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to transact: %d", result);
+            return false;
+        }
+        bool found = false;
+        result = reply.readBool(&found);
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to read: %d", result);
+            return false;
+        }
+        if (found) {
+            result = reply.read(*outTimestamps);
+            if (result != NO_ERROR) {
+                ALOGE("getFrameTimestamps failed to read timestamps: %d",
+                        result);
+                return false;
+            }
+        }
+        return found;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -88,6 +125,30 @@ status_t BnConsumerListener::onTransact(
             CHECK_INTERFACE(IConsumerListener, data, reply);
             onSidebandStreamChanged();
             return NO_ERROR; }
+        case GET_FRAME_TIMESTAMPS: {
+            CHECK_INTERFACE(IConsumerListener, data, reply);
+            uint64_t frameNumber = 0;
+            status_t result = data.readUint64(&frameNumber);
+            if (result != NO_ERROR) {
+                ALOGE("onTransact failed to read: %d", result);
+                return result;
+            }
+            FrameTimestamps timestamps;
+            bool found = getFrameTimestamps(frameNumber, &timestamps);
+            result = reply->writeBool(found);
+            if (result != NO_ERROR) {
+                ALOGE("onTransact failed to write: %d", result);
+                return result;
+            }
+            if (found) {
+                result = reply->write(timestamps);
+                if (result != NO_ERROR) {
+                    ALOGE("onTransact failed to write timestamps: %d", result);
+                    return result;
+                }
+            }
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
index cb1ad35..7c4379f 100644 (file)
@@ -51,6 +51,7 @@ enum {
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
     GET_SIDEBAND_STREAM,
+    GET_OCCUPANCY_HISTORY,
     DUMP,
 };
 
@@ -260,6 +261,31 @@ public:
         return stream;
     }
 
+    virtual status_t getOccupancyHistory(bool forceFlush,
+            std::vector<OccupancyTracker::Segment>* outHistory) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        status_t error = data.writeBool(forceFlush);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = remote()->transact(GET_OCCUPANCY_HISTORY, data,
+                &reply);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = reply.readParcelableVector(outHistory);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        status_t result = NO_ERROR;
+        error = reply.readInt32(&result);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        return result;
+    }
+
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -409,6 +435,25 @@ status_t BnGraphicBufferConsumer::onTransact(
             }
             return NO_ERROR;
         }
+        case GET_OCCUPANCY_HISTORY: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            bool forceFlush = false;
+            status_t error = data.readBool(&forceFlush);
+            if (error != NO_ERROR) {
+                return error;
+            }
+            std::vector<OccupancyTracker::Segment> history;
+            status_t result = getOccupancyHistory(forceFlush, &history);
+            error = reply->writeParcelableVector(history);
+            if (error != NO_ERROR) {
+                return error;
+            }
+            error = reply->writeInt32(result);
+            if (error != NO_ERROR) {
+                return error;
+            }
+            return NO_ERROR;
+        }
         case DUMP: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             String8 result = data.readString8();
index 2c48d83..9317eff 100644 (file)
@@ -55,6 +55,7 @@ enum {
     SET_AUTO_REFRESH,
     SET_DEQUEUE_TIMEOUT,
     GET_LAST_QUEUED_BUFFER,
+    GET_FRAME_TIMESTAMPS
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -418,6 +419,42 @@ public:
         *outFence = fence;
         return result;
     }
+
+    virtual bool getFrameTimestamps(uint64_t frameNumber,
+                FrameTimestamps* outTimestamps) const {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to write token: %d", result);
+            return false;
+        }
+        result = data.writeUint64(frameNumber);
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to write: %d", result);
+            return false;
+        }
+        result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to transact: %d", result);
+            return false;
+        }
+        bool found = false;
+        result = reply.readBool(&found);
+        if (result != NO_ERROR) {
+            ALOGE("getFrameTimestamps failed to read: %d", result);
+            return false;
+        }
+        if (found) {
+            result = reply.read(*outTimestamps);
+            if (result != NO_ERROR) {
+                ALOGE("getFrameTimestamps failed to read timestamps: %d",
+                        result);
+                return false;
+            }
+        }
+        return found;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -659,6 +696,30 @@ status_t BnGraphicBufferProducer::onTransact(
             }
             return NO_ERROR;
         }
+        case GET_FRAME_TIMESTAMPS: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            uint64_t frameNumber = 0;
+            status_t result = data.readUint64(&frameNumber);
+            if (result != NO_ERROR) {
+                ALOGE("onTransact failed to read: %d", result);
+                return result;
+            }
+            FrameTimestamps timestamps;
+            bool found = getFrameTimestamps(frameNumber, &timestamps);
+            result = reply->writeBool(found);
+            if (result != NO_ERROR) {
+                ALOGE("onTransact failed to write: %d", result);
+                return result;
+            }
+            if (found) {
+                result = reply->write(timestamps);
+                if (result != NO_ERROR) {
+                    ALOGE("onTransact failed to write timestamps: %d", result);
+                    return result;
+                }
+            }
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/OccupancyTracker.cpp b/libs/gui/OccupancyTracker.cpp
new file mode 100644 (file)
index 0000000..9687aaf
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "OccupancyTracker"
+
+#include <gui/OccupancyTracker.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+#include <inttypes.h>
+
+namespace android {
+
+status_t OccupancyTracker::Segment::writeToParcel(Parcel* parcel) const {
+    status_t result = parcel->writeInt64(totalTime);
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeUint64(static_cast<uint64_t>(numFrames));
+    if (result != OK) {
+        return result;
+    }
+    result = parcel->writeFloat(occupancyAverage);
+    if (result != OK) {
+        return result;
+    }
+    return parcel->writeBool(usedThirdBuffer);
+}
+
+status_t OccupancyTracker::Segment::readFromParcel(const Parcel* parcel) {
+    status_t result = parcel->readInt64(&totalTime);
+    if (result != OK) {
+        return result;
+    }
+    uint64_t uintNumFrames = 0;
+    result = parcel->readUint64(&uintNumFrames);
+    if (result != OK) {
+        return result;
+    }
+    numFrames = static_cast<size_t>(uintNumFrames);
+    result = parcel->readFloat(&occupancyAverage);
+    if (result != OK) {
+        return result;
+    }
+    return parcel->readBool(&usedThirdBuffer);
+}
+
+void OccupancyTracker::registerOccupancyChange(size_t occupancy) {
+    ATRACE_CALL();
+    nsecs_t now = systemTime();
+    nsecs_t delta = now - mLastOccupancyChangeTime;
+    if (delta > NEW_SEGMENT_DELAY) {
+        recordPendingSegment();
+    } else {
+        mPendingSegment.totalTime += delta;
+        if (mPendingSegment.mOccupancyTimes.count(mLastOccupancy)) {
+            mPendingSegment.mOccupancyTimes[mLastOccupancy] += delta;
+        } else {
+            mPendingSegment.mOccupancyTimes[mLastOccupancy] = delta;
+        }
+    }
+    if (occupancy > mLastOccupancy) {
+        ++mPendingSegment.numFrames;
+    }
+    mLastOccupancyChangeTime = now;
+    mLastOccupancy = occupancy;
+}
+
+std::vector<OccupancyTracker::Segment> OccupancyTracker::getSegmentHistory(
+        bool forceFlush) {
+    if (forceFlush) {
+        recordPendingSegment();
+    }
+    std::vector<Segment> segments(mSegmentHistory.cbegin(),
+            mSegmentHistory.cend());
+    mSegmentHistory.clear();
+    return segments;
+}
+
+void OccupancyTracker::recordPendingSegment() {
+    // Only record longer segments to get a better measurement of actual double-
+    // vs. triple-buffered time
+    if (mPendingSegment.numFrames > LONG_SEGMENT_THRESHOLD) {
+        float occupancyAverage = 0.0f;
+        bool usedThirdBuffer = false;
+        for (const auto& timePair : mPendingSegment.mOccupancyTimes) {
+            size_t occupancy = timePair.first;
+            float timeRatio = static_cast<float>(timePair.second) /
+                    mPendingSegment.totalTime;
+            occupancyAverage += timeRatio * occupancy;
+            usedThirdBuffer = usedThirdBuffer || (occupancy > 1);
+        }
+        mSegmentHistory.push_front({mPendingSegment.totalTime,
+                mPendingSegment.numFrames, occupancyAverage, usedThirdBuffer});
+        if (mSegmentHistory.size() > MAX_HISTORY_SIZE) {
+            mSegmentHistory.pop_back();
+        }
+    }
+    mPendingSegment.clear();
+}
+
+} // namespace android
index 9d130cd..4739ca4 100644 (file)
@@ -133,6 +133,39 @@ status_t Surface::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             outTransformMatrix);
 }
 
+bool Surface::getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
+        nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
+        nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+        nsecs_t* outReleaseTime) {
+    ATRACE_CALL();
+
+    FrameTimestamps timestamps;
+    bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
+            &timestamps);
+    if (found) {
+        if (outPostedTime) {
+            *outPostedTime = timestamps.postedTime;
+        }
+        if (outAcquireTime) {
+            *outAcquireTime = timestamps.acquireTime;
+        }
+        if (outRefreshStartTime) {
+            *outRefreshStartTime = timestamps.refreshStartTime;
+        }
+        if (outGlCompositionDoneTime) {
+            *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
+        }
+        if (outDisplayRetireTime) {
+            *outDisplayRetireTime = timestamps.displayRetireTime;
+        }
+        if (outReleaseTime) {
+            *outReleaseTime = timestamps.releaseTime;
+        }
+        return true;
+    }
+    return false;
+}
+
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
     Surface* c = getSelf(window);
     return c->setSwapInterval(interval);
@@ -617,6 +650,9 @@ int Surface::perform(int operation, va_list args)
     case NATIVE_WINDOW_SET_AUTO_REFRESH:
         res = dispatchSetAutoRefresh(args);
         break;
+    case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
+        res = dispatchGetFrameTimestamps(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -737,6 +773,20 @@ int Surface::dispatchSetAutoRefresh(va_list args) {
     return setAutoRefresh(autoRefresh);
 }
 
+int Surface::dispatchGetFrameTimestamps(va_list args) {
+    uint32_t framesAgo = va_arg(args, uint32_t);
+    nsecs_t* outPostedTime = va_arg(args, int64_t*);
+    nsecs_t* outAcquireTime = va_arg(args, int64_t*);
+    nsecs_t* outRefreshStartTime = va_arg(args, int64_t*);
+    nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
+    nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
+    nsecs_t* outReleaseTime = va_arg(args, int64_t*);
+    bool ret = getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
+            outPostedTime, outAcquireTime, outRefreshStartTime,
+            outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+    return ret ? NO_ERROR : BAD_VALUE;
+}
+
 int Surface::connect(int api) {
     static sp<IProducerListener> listener = new DummyProducerListener();
     return connect(api, listener);
index 85d63b4..210ce8c 100644 (file)
 
 #include <gtest/gtest.h>
 
+#include <thread>
+
+using namespace std::chrono_literals;
+
 namespace android {
 
 class BufferQueueTest : public ::testing::Test {
@@ -850,4 +854,140 @@ TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) {
             returnedBuffer->getNativeBuffer()->handle);
 }
 
+TEST_F(BufferQueueTest, TestOccupancyHistory) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+            NATIVE_WINDOW_API_CPU, false, &output));
+
+    int slot = BufferQueue::INVALID_BUFFER_SLOT;
+    sp<Fence> fence = Fence::NO_FENCE;
+    sp<GraphicBuffer> buffer = nullptr;
+    IGraphicBufferProducer::QueueBufferInput input(0ull, true,
+        HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+        NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+    BufferItem item{};
+
+    // Preallocate, dequeue, request, and cancel 3 buffers so we don't get
+    // BUFFER_NEEDS_REALLOCATION below
+    int slots[3] = {};
+    mProducer->setMaxDequeuedBufferCount(3);
+    for (size_t i = 0; i < 3; ++i) {
+        status_t result = mProducer->dequeueBuffer(&slots[i], &fence,
+                0, 0, 0, 0);
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+        ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer));
+    }
+    for (size_t i = 0; i < 3; ++i) {
+        ASSERT_EQ(OK, mProducer->cancelBuffer(slots[i], Fence::NO_FENCE));
+    }
+
+    // Create 3 segments
+
+    // The first segment is a two-buffer segment, so we only put one buffer into
+    // the queue at a time
+    for (size_t i = 0; i < 5; ++i) {
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+        ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+        ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+        std::this_thread::sleep_for(16ms);
+    }
+
+    // Sleep between segments
+    std::this_thread::sleep_for(500ms);
+
+    // The second segment is a double-buffer segment. It starts the same as the
+    // two-buffer segment, but then at the end, we put two buffers in the queue
+    // at the same time before draining it.
+    for (size_t i = 0; i < 5; ++i) {
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+        ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+        ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+        std::this_thread::sleep_for(16ms);
+    }
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+    std::this_thread::sleep_for(16ms);
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Sleep between segments
+    std::this_thread::sleep_for(500ms);
+
+    // The third segment is a triple-buffer segment, so the queue is switching
+    // between one buffer and two buffers deep.
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+    for (size_t i = 0; i < 5; ++i) {
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+        ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+        ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+        std::this_thread::sleep_for(16ms);
+    }
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Now we read the segments
+    std::vector<OccupancyTracker::Segment> history;
+    ASSERT_EQ(OK, mConsumer->getOccupancyHistory(false, &history));
+
+    // Since we didn't force a flush, we should only get the first two segments
+    // (since the third segment hasn't been closed out by the appearance of a
+    // new segment yet)
+    ASSERT_EQ(2u, history.size());
+
+    // The first segment (which will be history[1], since the newest segment
+    // should be at the front of the vector) should be a two-buffer segment,
+    // which implies that the occupancy average should be between 0 and 1, and
+    // usedThirdBuffer should be false
+    const auto& firstSegment = history[1];
+    ASSERT_EQ(5u, firstSegment.numFrames);
+    ASSERT_LT(0, firstSegment.occupancyAverage);
+    ASSERT_GT(1, firstSegment.occupancyAverage);
+    ASSERT_EQ(false, firstSegment.usedThirdBuffer);
+
+    // The second segment should be a double-buffered segment, which implies that
+    // the occupancy average should be between 0 and 1, but usedThirdBuffer
+    // should be true
+    const auto& secondSegment = history[0];
+    ASSERT_EQ(7u, secondSegment.numFrames);
+    ASSERT_LT(0, secondSegment.occupancyAverage);
+    ASSERT_GT(1, secondSegment.occupancyAverage);
+    ASSERT_EQ(true, secondSegment.usedThirdBuffer);
+
+    // If we read the segments again without flushing, we shouldn't get any new
+    // segments
+    ASSERT_EQ(OK, mConsumer->getOccupancyHistory(false, &history));
+    ASSERT_EQ(0u, history.size());
+
+    // Read the segments again, this time forcing a flush so we get the third
+    // segment
+    ASSERT_EQ(OK, mConsumer->getOccupancyHistory(true, &history));
+    ASSERT_EQ(1u, history.size());
+
+    // This segment should be a triple-buffered segment, which implies that the
+    // occupancy average should be between 1 and 2, and usedThirdBuffer should
+    // be true
+    const auto& thirdSegment = history[0];
+    ASSERT_EQ(6u, thirdSegment.numFrames);
+    ASSERT_LT(1, thirdSegment.occupancyAverage);
+    ASSERT_GT(2, thirdSegment.occupancyAverage);
+    ASSERT_EQ(true, thirdSegment.usedThirdBuffer);
+}
+
 } // namespace android
index ee6c093..e690ede 100644 (file)
@@ -17,7 +17,7 @@ include $(CLEAR_VARS)
 
 LOCAL_CLANG := true
 LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-LOCAL_SANITIZE := integer
+LOCAL_SANITIZE := integer
 
 # The static constructors and destructors in this library have not been noted to
 # introduce significant overheads
@@ -37,6 +37,8 @@ LOCAL_CPPFLAGS += -Wno-padded
 LOCAL_SRC_FILES := \
        Fence.cpp \
        FrameStats.cpp \
+       Gralloc1.cpp \
+       Gralloc1On0Adapter.cpp \
        GraphicBuffer.cpp \
        GraphicBufferAllocator.cpp \
        GraphicBufferMapper.cpp \
diff --git a/libs/ui/Gralloc1.cpp b/libs/ui/Gralloc1.cpp
new file mode 100644 (file)
index 0000000..4c73ce4
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2016 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include <ui/Gralloc1.h>
+
+#include <vector>
+
+#undef LOG_TAG
+#define LOG_TAG GRALLOC1_LOG_TAG
+
+namespace android {
+
+namespace Gralloc1 {
+
+Descriptor::~Descriptor()
+{
+    int32_t intError = mShimDevice.mFunctions.destroyDescriptor(
+            mShimDevice.mDevice, mDeviceId);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("destroyDescriptor failed: %d", intError);
+    }
+}
+
+gralloc1_error_t Descriptor::setDimensions(uint32_t width, uint32_t height)
+{
+    int32_t intError = mShimDevice.mFunctions.setDimensions(mShimDevice.mDevice,
+            mDeviceId, width, height);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+    mWidth = width;
+    mHeight = height;
+    return error;
+}
+
+template <typename ApiType>
+struct Setter {
+    typedef int32_t (*Type)(gralloc1_device_t*, gralloc1_buffer_descriptor_t,
+            ApiType);
+};
+
+template <typename ApiType, typename ValueType>
+static inline gralloc1_error_t setHelper(
+        typename Setter<ApiType>::Type setter, gralloc1_device_t* device,
+        gralloc1_buffer_descriptor_t id, ValueType newValue,
+        ValueType* cacheVariable)
+{
+    int32_t intError = setter(device, id, static_cast<ApiType>(newValue));
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+    *cacheVariable = newValue;
+    return error;
+}
+
+gralloc1_error_t Descriptor::setFormat(android_pixel_format_t format)
+{
+    return setHelper<int32_t>(mShimDevice.mFunctions.setFormat.pfn,
+            mShimDevice.mDevice, mDeviceId, format, &mFormat);
+}
+
+gralloc1_error_t Descriptor::setProducerUsage(gralloc1_producer_usage_t usage)
+{
+    return setHelper<uint64_t>(mShimDevice.mFunctions.setProducerUsage.pfn,
+            mShimDevice.mDevice, mDeviceId, usage, &mProducerUsage);
+}
+
+gralloc1_error_t Descriptor::setConsumerUsage(gralloc1_consumer_usage_t usage)
+{
+    return setHelper<uint64_t>(mShimDevice.mFunctions.setConsumerUsage.pfn,
+            mShimDevice.mDevice, mDeviceId, usage, &mConsumerUsage);
+}
+
+Device::Device(gralloc1_device_t* device)
+  : mDevice(device),
+    mCapabilities(loadCapabilities()),
+    mFunctions()
+{
+    if (!loadFunctions()) {
+        ALOGE("Failed to load a required function, aborting");
+        abort();
+    }
+}
+
+bool Device::hasCapability(gralloc1_capability_t capability) const
+{
+    return mCapabilities.count(capability) > 0;
+}
+
+std::string Device::dump()
+{
+    uint32_t length = 0;
+    mFunctions.dump(mDevice, &length, nullptr);
+
+    std::vector<char> output;
+    output.resize(length);
+    mFunctions.dump(mDevice, &length, output.data());
+
+    return std::string(output.cbegin(), output.cend());
+}
+
+std::shared_ptr<Descriptor> Device::createDescriptor()
+{
+    gralloc1_buffer_descriptor_t descriptorId;
+    int32_t intError = mFunctions.createDescriptor(mDevice, &descriptorId);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return nullptr;
+    }
+    auto descriptor = std::make_shared<Descriptor>(*this, descriptorId);
+    return descriptor;
+}
+
+gralloc1_error_t Device::getStride(buffer_handle_t buffer, uint32_t* outStride)
+{
+    int32_t intError = mFunctions.getStride(mDevice, buffer, outStride);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+static inline bool allocationSucceded(gralloc1_error_t error)
+{
+    return error == GRALLOC1_ERROR_NONE || error == GRALLOC1_ERROR_NOT_SHARED;
+}
+
+gralloc1_error_t Device::allocate(
+        const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
+        std::vector<buffer_handle_t>* outBuffers)
+{
+    if (mFunctions.allocate.pfn == nullptr) {
+        // Allocation is not supported on this device
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    std::vector<gralloc1_buffer_descriptor_t> deviceIds;
+    for (const auto& descriptor : descriptors) {
+        deviceIds.emplace_back(descriptor->getDeviceId());
+    }
+
+    std::vector<buffer_handle_t> buffers(descriptors.size());
+    int32_t intError = mFunctions.allocate(mDevice,
+            static_cast<uint32_t>(descriptors.size()), deviceIds.data(),
+            buffers.data());
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (allocationSucceded(error)) {
+        *outBuffers = std::move(buffers);
+    }
+
+    return error;
+}
+
+gralloc1_error_t Device::allocate(
+        const std::shared_ptr<const Descriptor>& descriptor,
+        gralloc1_backing_store_t id, buffer_handle_t* outBuffer)
+{
+    gralloc1_error_t error = GRALLOC1_ERROR_NONE;
+
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        buffer_handle_t buffer = nullptr;
+        int32_t intError = mFunctions.allocateWithId(mDevice,
+                descriptor->getDeviceId(), id, &buffer);
+        error = static_cast<gralloc1_error_t>(intError);
+        if (allocationSucceded(error)) {
+            *outBuffer = buffer;
+        }
+    } else {
+        std::vector<std::shared_ptr<const Descriptor>> descriptors;
+        descriptors.emplace_back(descriptor);
+        std::vector<buffer_handle_t> buffers;
+        error = allocate(descriptors, &buffers);
+        if (allocationSucceded(error)) {
+            *outBuffer = buffers[0];
+        }
+    }
+
+    return error;
+}
+
+gralloc1_error_t Device::retain(buffer_handle_t buffer)
+{
+    int32_t intError = mFunctions.retain(mDevice, buffer);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::retain(const GraphicBuffer* buffer)
+{
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        return mFunctions.retainGraphicBuffer(mDevice, buffer);
+    } else {
+        return retain(buffer->getNativeBuffer()->handle);
+    }
+}
+
+gralloc1_error_t Device::release(buffer_handle_t buffer)
+{
+    int32_t intError = mFunctions.release(mDevice, buffer);
+    return static_cast<gralloc1_error_t>(intError);
+}
+
+gralloc1_error_t Device::getNumFlexPlanes(buffer_handle_t buffer,
+        uint32_t* outNumPlanes)
+{
+    uint32_t numPlanes = 0;
+    int32_t intError = mFunctions.getNumFlexPlanes(mDevice, buffer, &numPlanes);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outNumPlanes = numPlanes;
+    }
+    return error;
+}
+
+gralloc1_error_t Device::lock(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion, void** outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lock(%p)", buffer);
+    return lockHelper(mFunctions.lock.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockFlex(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion,
+        struct android_flex_layout* outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lockFlex(%p)", buffer);
+    return lockHelper(mFunctions.lockFlex.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::lockYCbCr(buffer_handle_t buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t* accessRegion,
+        struct android_ycbcr* outData,
+        const sp<Fence>& acquireFence)
+{
+    ALOGV("Calling lockYCbCr(%p)", buffer);
+    return lockHelper(mFunctions.lockYCbCr.pfn, buffer, producerUsage,
+            consumerUsage, accessRegion, outData, acquireFence);
+}
+
+gralloc1_error_t Device::unlock(buffer_handle_t buffer, sp<Fence>* outFence)
+{
+    int32_t fenceFd = -1;
+    int32_t intError = mFunctions.unlock(mDevice, buffer, &fenceFd);
+    auto error = static_cast<gralloc1_error_t>(intError);
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outFence = new Fence(fenceFd);
+    }
+    return error;
+}
+
+std::unordered_set<gralloc1_capability_t> Device::loadCapabilities()
+{
+    std::vector<int32_t> intCapabilities;
+    uint32_t numCapabilities = 0;
+    mDevice->getCapabilities(mDevice, &numCapabilities, nullptr);
+
+    intCapabilities.resize(numCapabilities);
+    mDevice->getCapabilities(mDevice, &numCapabilities, intCapabilities.data());
+
+    std::unordered_set<gralloc1_capability_t> capabilities;
+    for (const auto intCapability : intCapabilities) {
+        capabilities.emplace(static_cast<gralloc1_capability_t>(intCapability));
+    }
+    return capabilities;
+}
+
+bool Device::loadFunctions()
+{
+    // Functions which must always be present
+    if (!mFunctions.dump.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.createDescriptor.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.destroyDescriptor.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setConsumerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setDimensions.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setFormat.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.setProducerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getBackingStore.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getConsumerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getDimensions.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getFormat.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getProducerUsage.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getStride.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.retain.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.release.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.getNumFlexPlanes.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.lock.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.lockFlex.load(mDevice, true)) {
+        return false;
+    }
+    if (!mFunctions.unlock.load(mDevice, true)) {
+        return false;
+    }
+
+    if (hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        // These should always be present on the adapter
+        if (!mFunctions.retainGraphicBuffer.load(mDevice, true)) {
+            return false;
+        }
+        if (!mFunctions.lockYCbCr.load(mDevice, true)) {
+            return false;
+        }
+
+        // allocateWithId may not be present if we're only able to map in this
+        // process
+        mFunctions.allocateWithId.load(mDevice, false);
+    } else {
+        // allocate may not be present if we're only able to map in this process
+        mFunctions.allocate.load(mDevice, false);
+    }
+
+    return true;
+}
+
+std::unique_ptr<Gralloc1On0Adapter> Loader::mAdapter = nullptr;
+
+Loader::Loader()
+  : mDevice(nullptr)
+{
+    hw_module_t const* module;
+    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+    uint8_t majorVersion = (module->module_api_version >> 8) & 0xFF;
+    uint8_t minorVersion = module->module_api_version & 0xFF;
+    gralloc1_device_t* device = nullptr;
+    if (majorVersion == 1) {
+        gralloc1_open(module, &device);
+    } else {
+        if (!mAdapter) {
+            mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
+        }
+        device = mAdapter->getDevice();
+    }
+    mDevice = std::make_unique<Gralloc1::Device>(device);
+}
+
+Loader::~Loader() {}
+
+std::unique_ptr<Device> Loader::getDevice()
+{
+    return std::move(mDevice);
+}
+
+} // namespace android::Gralloc1
+
+} // namespace android
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
new file mode 100644 (file)
index 0000000..6e69df1
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Gralloc1On0Adapter"
+//#define LOG_NDEBUG 0
+
+#include <hardware/gralloc.h>
+
+#include <ui/Gralloc1On0Adapter.h>
+
+#include <utils/Log.h>
+
+#include <inttypes.h>
+
+template <typename PFN, typename T>
+static gralloc1_function_pointer_t asFP(T function)
+{
+    static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer");
+    return reinterpret_cast<gralloc1_function_pointer_t>(function);
+}
+
+namespace android {
+
+Gralloc1On0Adapter::Gralloc1On0Adapter(const hw_module_t* module)
+  : mModule(reinterpret_cast<const gralloc_module_t*>(module)),
+    mMinorVersion(mModule->common.module_api_version & 0xFF),
+    mDevice(nullptr)
+{
+    ALOGV("Constructing");
+    getCapabilities = getCapabilitiesHook;
+    getFunction = getFunctionHook;
+    int error = ::gralloc_open(&(mModule->common), &mDevice);
+    if (error) {
+        ALOGE("Failed to open gralloc0 module: %d", error);
+    }
+    ALOGV("Opened gralloc0 device %p", mDevice);
+}
+
+Gralloc1On0Adapter::~Gralloc1On0Adapter()
+{
+    ALOGV("Destructing");
+    if (mDevice) {
+        ALOGV("Closing gralloc0 device %p", mDevice);
+        ::gralloc_close(mDevice);
+    }
+}
+
+void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount,
+        int32_t* outCapabilities)
+{
+    if (outCapabilities == nullptr) {
+        *outCount = 1;
+        return;
+    }
+    if (*outCount >= 1) {
+        *outCapabilities = GRALLOC1_CAPABILITY_ON_ADAPTER;
+        *outCount = 1;
+    }
+}
+
+gralloc1_function_pointer_t Gralloc1On0Adapter::doGetFunction(
+        int32_t intDescriptor)
+{
+    constexpr auto lastDescriptor =
+            static_cast<int32_t>(GRALLOC1_LAST_ADAPTER_FUNCTION);
+    if (intDescriptor < 0 || intDescriptor > lastDescriptor) {
+        ALOGE("Invalid function descriptor");
+        return nullptr;
+    }
+
+    auto descriptor =
+            static_cast<gralloc1_function_descriptor_t>(intDescriptor);
+    switch (descriptor) {
+        case GRALLOC1_FUNCTION_DUMP:
+            return asFP<GRALLOC1_PFN_DUMP>(dumpHook);
+        case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR:
+            return asFP<GRALLOC1_PFN_CREATE_DESCRIPTOR>(createDescriptorHook);
+        case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR:
+            return asFP<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(destroyDescriptorHook);
+        case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE:
+            return asFP<GRALLOC1_PFN_SET_CONSUMER_USAGE>(setConsumerUsageHook);
+        case GRALLOC1_FUNCTION_SET_DIMENSIONS:
+            return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook);
+        case GRALLOC1_FUNCTION_SET_FORMAT:
+            return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook);
+        case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE:
+            return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook);
+        case GRALLOC1_FUNCTION_GET_BACKING_STORE:
+            return asFP<GRALLOC1_PFN_GET_BACKING_STORE>(
+                    bufferHook<decltype(&Buffer::getBackingStore),
+                    &Buffer::getBackingStore, gralloc1_backing_store_t*>);
+        case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE:
+            return asFP<GRALLOC1_PFN_GET_CONSUMER_USAGE>(getConsumerUsageHook);
+        case GRALLOC1_FUNCTION_GET_DIMENSIONS:
+            return asFP<GRALLOC1_PFN_GET_DIMENSIONS>(
+                    bufferHook<decltype(&Buffer::getDimensions),
+                    &Buffer::getDimensions, uint32_t*, uint32_t*>);
+        case GRALLOC1_FUNCTION_GET_FORMAT:
+            return asFP<GRALLOC1_PFN_GET_FORMAT>(
+                    bufferHook<decltype(&Buffer::getFormat),
+                    &Buffer::getFormat, int32_t*>);
+        case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE:
+            return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook);
+        case GRALLOC1_FUNCTION_GET_STRIDE:
+            return asFP<GRALLOC1_PFN_GET_STRIDE>(
+                    bufferHook<decltype(&Buffer::getStride),
+                    &Buffer::getStride, uint32_t*>);
+        case GRALLOC1_FUNCTION_ALLOCATE:
+            // Not provided, since we'll use ALLOCATE_WITH_ID
+            return nullptr;
+        case GRALLOC1_FUNCTION_ALLOCATE_WITH_ID:
+            if (mDevice != nullptr) {
+                return asFP<GRALLOC1_PFN_ALLOCATE_WITH_ID>(allocateWithIdHook);
+            } else {
+                return nullptr;
+            }
+        case GRALLOC1_FUNCTION_RETAIN:
+            return asFP<GRALLOC1_PFN_RETAIN>(
+                    managementHook<&Gralloc1On0Adapter::retain>);
+        case GRALLOC1_FUNCTION_RELEASE:
+            return asFP<GRALLOC1_PFN_RELEASE>(
+                    managementHook<&Gralloc1On0Adapter::release>);
+        case GRALLOC1_FUNCTION_RETAIN_GRAPHIC_BUFFER:
+            return asFP<GRALLOC1_PFN_RETAIN_GRAPHIC_BUFFER>(
+                    retainGraphicBufferHook);
+        case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES:
+            return asFP<GRALLOC1_PFN_GET_NUM_FLEX_PLANES>(
+                    bufferHook<decltype(&Buffer::getNumFlexPlanes),
+                    &Buffer::getNumFlexPlanes, uint32_t*>);
+        case GRALLOC1_FUNCTION_LOCK:
+            return asFP<GRALLOC1_PFN_LOCK>(
+                    lockHook<void*, &Gralloc1On0Adapter::lock>);
+        case GRALLOC1_FUNCTION_LOCK_FLEX:
+            return asFP<GRALLOC1_PFN_LOCK_FLEX>(
+                    lockHook<struct android_flex_layout,
+                    &Gralloc1On0Adapter::lockFlex>);
+        case GRALLOC1_FUNCTION_LOCK_YCBCR:
+            return asFP<GRALLOC1_PFN_LOCK_YCBCR>(
+                    lockHook<struct android_ycbcr,
+                    &Gralloc1On0Adapter::lockYCbCr>);
+        case GRALLOC1_FUNCTION_UNLOCK:
+            return asFP<GRALLOC1_PFN_UNLOCK>(unlockHook);
+        case GRALLOC1_FUNCTION_INVALID:
+            ALOGE("Invalid function descriptor");
+            return nullptr;
+    }
+
+    ALOGE("Unknown function descriptor: %d", intDescriptor);
+    return nullptr;
+}
+
+void Gralloc1On0Adapter::dump(uint32_t* outSize, char* outBuffer)
+{
+    ALOGV("dump(%u (%p), %p", outSize ? *outSize : 0, outSize, outBuffer);
+
+    if (!mDevice->dump) {
+        // dump is optional on gralloc0 implementations
+        *outSize = 0;
+        return;
+    }
+
+    if (!outBuffer) {
+        constexpr int32_t BUFFER_LENGTH = 4096;
+        char buffer[BUFFER_LENGTH] = {};
+        mDevice->dump(mDevice, buffer, BUFFER_LENGTH);
+        buffer[BUFFER_LENGTH - 1] = 0; // Ensure the buffer is null-terminated
+        size_t actualLength = std::strlen(buffer);
+        mCachedDump.resize(actualLength);
+        std::copy_n(buffer, actualLength, mCachedDump.begin());
+        *outSize = static_cast<uint32_t>(actualLength);
+    } else {
+        *outSize = std::min(*outSize,
+                static_cast<uint32_t>(mCachedDump.size()));
+        outBuffer = std::copy_n(mCachedDump.cbegin(), *outSize, outBuffer);
+    }
+}
+
+gralloc1_error_t Gralloc1On0Adapter::createDescriptor(
+        gralloc1_buffer_descriptor_t* outDescriptor)
+{
+    auto descriptorId = sNextBufferDescriptorId++;
+    mDescriptors.emplace(descriptorId,
+            std::make_shared<Descriptor>(this, descriptorId));
+
+    ALOGV("Created descriptor %" PRIu64, descriptorId);
+
+    *outDescriptor = descriptorId;
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::destroyDescriptor(
+        gralloc1_buffer_descriptor_t descriptor)
+{
+    ALOGV("Destroying descriptor %" PRIu64, descriptor);
+
+    if (mDescriptors.count(descriptor) == 0) {
+        return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+    }
+
+    mDescriptors.erase(descriptor);
+    return GRALLOC1_ERROR_NONE;
+}
+
+Gralloc1On0Adapter::Buffer::Buffer(buffer_handle_t handle,
+        gralloc1_backing_store_t store, const Descriptor& descriptor,
+        uint32_t stride, bool wasAllocated)
+  : mHandle(handle),
+    mReferenceCount(1),
+    mStore(store),
+    mDescriptor(descriptor),
+    mStride(stride),
+    mWasAllocated(wasAllocated) {}
+
+gralloc1_error_t Gralloc1On0Adapter::allocate(
+        const std::shared_ptr<Descriptor>& descriptor,
+        gralloc1_backing_store_t store,
+        buffer_handle_t* outBufferHandle)
+{
+    ALOGV("allocate(%" PRIu64 ", %#" PRIx64 ")", descriptor->id, store);
+
+    // If this function is being called, it's because we handed out its function
+    // pointer, which only occurs when mDevice has been loaded successfully and
+    // we are permitted to allocate
+
+    int usage = static_cast<int>(descriptor->producerUsage) |
+            static_cast<int>(descriptor->consumerUsage);
+    buffer_handle_t handle = nullptr;
+    int stride = 0;
+    ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width,
+            descriptor->height, descriptor->format, usage);
+    auto error = mDevice->alloc(mDevice,
+            static_cast<int>(descriptor->width),
+            static_cast<int>(descriptor->height), descriptor->format,
+            usage, &handle, &stride);
+    if (error != 0) {
+        ALOGE("gralloc0 allocation failed: %d (%s)", error,
+                strerror(-error));
+        return GRALLOC1_ERROR_NO_RESOURCES;
+    }
+
+    *outBufferHandle = handle;
+    auto buffer = std::make_shared<Buffer>(handle, store, *descriptor, stride,
+            true);
+    mBuffers.emplace(handle, std::move(buffer));
+
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::allocateWithIdHook(
+        gralloc1_device_t* device, gralloc1_buffer_descriptor_t descriptorId,
+        gralloc1_backing_store_t store, buffer_handle_t* outBuffer)
+{
+    auto adapter = getAdapter(device);
+
+    auto descriptor = adapter->getDescriptor(descriptorId);
+    if (!descriptor) {
+        return GRALLOC1_ERROR_BAD_DESCRIPTOR;
+    }
+
+    buffer_handle_t bufferHandle = nullptr;
+    auto error = adapter->allocate(descriptor, store, &bufferHandle);
+    if (error != GRALLOC1_ERROR_NONE) {
+        return error;
+    }
+
+    *outBuffer = bufferHandle;
+    return error;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+        const std::shared_ptr<Buffer>& buffer)
+{
+    buffer->retain();
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::release(
+        const std::shared_ptr<Buffer>& buffer)
+{
+    if (!buffer->release()) {
+        return GRALLOC1_ERROR_NONE;
+    }
+
+    buffer_handle_t handle = buffer->getHandle();
+    if (buffer->wasAllocated()) {
+        ALOGV("Calling free(%p)", handle);
+        int result = mDevice->free(mDevice, handle);
+        if (result != 0) {
+            ALOGE("gralloc0 free failed: %d", result);
+        }
+    } else {
+        ALOGV("Calling unregisterBuffer(%p)", handle);
+        int result = mModule->unregisterBuffer(mModule, handle);
+        if (result != 0) {
+            ALOGE("gralloc0 unregister failed: %d", result);
+        }
+    }
+    mBuffers.erase(handle);
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::retain(
+        const android::GraphicBuffer* graphicBuffer)
+{
+    ALOGV("retainGraphicBuffer(%p, %#" PRIx64 ")",
+            graphicBuffer->getNativeBuffer()->handle, graphicBuffer->getId());
+
+    buffer_handle_t handle = graphicBuffer->getNativeBuffer()->handle;
+    if (mBuffers.count(handle) != 0) {
+        mBuffers[handle]->retain();
+        return GRALLOC1_ERROR_NONE;
+    }
+
+    ALOGV("Calling registerBuffer(%p)", handle);
+    int result = mModule->registerBuffer(mModule, handle);
+    if (result != 0) {
+        ALOGE("gralloc0 register failed: %d", result);
+        return GRALLOC1_ERROR_NO_RESOURCES;
+    }
+
+    Descriptor descriptor{this, sNextBufferDescriptorId++};
+    descriptor.setDimensions(graphicBuffer->getWidth(),
+            graphicBuffer->getHeight());
+    descriptor.setFormat(graphicBuffer->getPixelFormat());
+    descriptor.setProducerUsage(
+            static_cast<gralloc1_producer_usage_t>(graphicBuffer->getUsage()));
+    descriptor.setConsumerUsage(
+            static_cast<gralloc1_consumer_usage_t>(graphicBuffer->getUsage()));
+    auto buffer = std::make_shared<Buffer>(handle,
+            static_cast<gralloc1_backing_store_t>(graphicBuffer->getId()),
+            descriptor, graphicBuffer->getStride(), false);
+    mBuffers.emplace(handle, std::move(buffer));
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lock(
+        const std::shared_ptr<Buffer>& buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t& accessRegion, void** outData,
+        const sp<Fence>& acquireFence)
+{
+    if (mMinorVersion >= 3) {
+        int result = mModule->lockAsync(mModule, buffer->getHandle(),
+                static_cast<int32_t>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData, acquireFence->dup());
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    } else {
+        acquireFence->waitForever("Gralloc1On0Adapter::lock");
+        int result = mModule->lock(mModule, buffer->getHandle(),
+                static_cast<int32_t>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData);
+        ALOGV("gralloc0 lock returned %d", result);
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    }
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockFlex(
+        const std::shared_ptr<Buffer>& /*buffer*/,
+        gralloc1_producer_usage_t /*producerUsage*/,
+        gralloc1_consumer_usage_t /*consumerUsage*/,
+        const gralloc1_rect_t& /*accessRegion*/,
+        struct android_flex_layout* /*outData*/,
+        const sp<Fence>& /*acquireFence*/)
+{
+    // TODO
+    return GRALLOC1_ERROR_UNSUPPORTED;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::lockYCbCr(
+        const std::shared_ptr<Buffer>& buffer,
+        gralloc1_producer_usage_t producerUsage,
+        gralloc1_consumer_usage_t consumerUsage,
+        const gralloc1_rect_t& accessRegion, struct android_ycbcr* outData,
+        const sp<Fence>& acquireFence)
+{
+    if (mMinorVersion >= 3 && mModule->lockAsync_ycbcr) {
+        int result = mModule->lockAsync_ycbcr(mModule, buffer->getHandle(),
+                static_cast<int>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData, acquireFence->dup());
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    } else if (mModule->lock_ycbcr) {
+        acquireFence->waitForever("Gralloc1On0Adapter::lockYCbCr");
+        int result = mModule->lock_ycbcr(mModule, buffer->getHandle(),
+                static_cast<int>(producerUsage | consumerUsage),
+                accessRegion.left, accessRegion.top, accessRegion.width,
+                accessRegion.height, outData);
+        ALOGV("gralloc0 lockYCbCr returned %d", result);
+        if (result != 0) {
+            return GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    } else {
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    return GRALLOC1_ERROR_NONE;
+}
+
+gralloc1_error_t Gralloc1On0Adapter::unlock(
+        const std::shared_ptr<Buffer>& buffer,
+        sp<Fence>* outReleaseFence)
+{
+    if (mMinorVersion >= 3) {
+        int fenceFd = -1;
+        int result = mModule->unlockAsync(mModule, buffer->getHandle(),
+                &fenceFd);
+        if (result != 0) {
+            close(fenceFd);
+            ALOGE("gralloc0 unlockAsync failed: %d", result);
+        } else {
+            *outReleaseFence = new Fence(fenceFd);
+        }
+    } else {
+        int result = mModule->unlock(mModule, buffer->getHandle());
+        if (result != 0) {
+            ALOGE("gralloc0 unlock failed: %d", result);
+        }
+    }
+    return GRALLOC1_ERROR_NONE;
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Descriptor>
+Gralloc1On0Adapter::getDescriptor(gralloc1_buffer_descriptor_t descriptorId)
+{
+    if (mDescriptors.count(descriptorId) == 0) {
+        return nullptr;
+    }
+
+    return mDescriptors[descriptorId];
+}
+
+std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer(
+        buffer_handle_t bufferHandle)
+{
+    if (mBuffers.count(bufferHandle) == 0) {
+        return nullptr;
+    }
+
+    return mBuffers[bufferHandle];
+}
+
+std::atomic<gralloc1_buffer_descriptor_t>
+        Gralloc1On0Adapter::sNextBufferDescriptorId(1);
+
+} // namespace android
index 4fe0946..f28af6e 100644 (file)
@@ -169,8 +169,8 @@ status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
 {
     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
     uint32_t outStride = 0;
-    status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,
-            &handle, &outStride);
+    status_t err = allocator.allocate(inWidth, inHeight, inFormat, inUsage,
+            &handle, &outStride, mId);
     if (err == NO_ERROR) {
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
@@ -390,7 +390,7 @@ status_t GraphicBuffer::unflatten(
     mOwner = ownHandle;
 
     if (handle != 0) {
-        status_t err = mBufferMapper.registerBuffer(handle);
+        status_t err = mBufferMapper.registerBuffer(this);
         if (err != NO_ERROR) {
             width = height = stride = format = usage = 0;
             handle = NULL;
index 9b265af..3b83fb6 100644 (file)
@@ -25,6 +25,7 @@
 #include <utils/Trace.h>
 
 #include <ui/GraphicBufferAllocator.h>
+#include <ui/Gralloc1On0Adapter.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -36,20 +37,10 @@ KeyedVector<buffer_handle_t,
     GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
 
 GraphicBufferAllocator::GraphicBufferAllocator()
-    : mAllocDev(0)
-{
-    hw_module_t const* module;
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        gralloc_open(module, &mAllocDev);
-    }
-}
+  : mLoader(std::make_unique<Gralloc1::Loader>()),
+    mDevice(mLoader->getDevice()) {}
 
-GraphicBufferAllocator::~GraphicBufferAllocator()
-{
-    gralloc_close(mAllocDev);
-}
+GraphicBufferAllocator::~GraphicBufferAllocator() {}
 
 void GraphicBufferAllocator::dump(String8& result) const
 {
@@ -77,10 +68,8 @@ void GraphicBufferAllocator::dump(String8& result) const
     }
     snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
     result.append(buffer);
-    if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
-        mAllocDev->dump(mAllocDev, buffer, SIZE);
-        result.append(buffer);
-    }
+    std::string deviceDump = mDevice->dump();
+    result.append(deviceDump.c_str(), deviceDump.size());
 }
 
 void GraphicBufferAllocator::dumpToSystemLog()
@@ -90,9 +79,9 @@ void GraphicBufferAllocator::dumpToSystemLog()
     ALOGD("%s", s.string());
 }
 
-status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
+status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
         PixelFormat format, uint32_t usage, buffer_handle_t* handle,
-        uint32_t* stride)
+        uint32_t* stride, uint64_t graphicBufferId)
 {
     ATRACE_CALL();
 
@@ -101,22 +90,46 @@ status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
     if (!width || !height)
         width = height = 1;
 
-    // we have a h/w allocator and h/w buffer is requested
-    status_t err;
-
     // Filter out any usage bits that should not be passed to the gralloc module
     usage &= GRALLOC_USAGE_ALLOC_MASK;
 
-    int outStride = 0;
-    err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
-            static_cast<int>(height), format, static_cast<int>(usage), handle,
-            &outStride);
-    *stride = static_cast<uint32_t>(outStride);
+    auto descriptor = mDevice->createDescriptor();
+    auto error = descriptor->setDimensions(width, height);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set dimensions to (%u, %u): %d", width, height, error);
+        return BAD_VALUE;
+    }
+    error = descriptor->setFormat(static_cast<android_pixel_format_t>(format));
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set format to %d: %d", format, error);
+        return BAD_VALUE;
+    }
+    error = descriptor->setProducerUsage(
+            static_cast<gralloc1_producer_usage_t>(usage));
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set producer usage to %u: %d", usage, error);
+        return BAD_VALUE;
+    }
+    error = descriptor->setConsumerUsage(
+            static_cast<gralloc1_consumer_usage_t>(usage));
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to set consumer usage to %u: %d", usage, error);
+        return BAD_VALUE;
+    }
 
-    ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
-            width, height, format, usage, err, strerror(-err));
+    error = mDevice->allocate(descriptor, graphicBufferId, handle);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
+                width, height, format, usage, error);
+        return NO_MEMORY;
+    }
 
-    if (err == NO_ERROR) {
+    error = mDevice->getStride(*handle, stride);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGW("Failed to get stride from buffer: %d", error);
+    }
+
+    if (error == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
         uint32_t bpp = bytesPerPixel(format);
@@ -130,24 +143,23 @@ status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
         list.add(*handle, rec);
     }
 
-    return err;
+    return NO_ERROR;
 }
 
 status_t GraphicBufferAllocator::free(buffer_handle_t handle)
 {
     ATRACE_CALL();
-    status_t err;
-
-    err = mAllocDev->free(mAllocDev, handle);
 
-    ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
-    if (err == NO_ERROR) {
-        Mutex::Autolock _l(sLock);
-        KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
-        list.removeItem(handle);
+    auto error = mDevice->release(handle);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("Failed to free buffer: %d", error);
     }
 
-    return err;
+    Mutex::Autolock _l(sLock);
+    KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+    list.removeItem(handle);
+
+    return NO_ERROR;
 }
 
 // ---------------------------------------------------------------------------
index 90a1c11..481d43c 100644 (file)
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "GraphicBufferMapper"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
 
 #include <stdint.h>
 #include <errno.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include <ui/Gralloc1On0Adapter.h>
 #include <ui/GraphicBufferMapper.h>
 #include <ui/Rect.h>
 
-#include <hardware/gralloc.h>
-
+#include <system/graphics.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -43,151 +44,247 @@ namespace android {
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
 
 GraphicBufferMapper::GraphicBufferMapper()
-    : mAllocMod(0)
-{
-    hw_module_t const* module;
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        mAllocMod = reinterpret_cast<gralloc_module_t const *>(module);
-    }
-}
+  : mLoader(std::make_unique<Gralloc1::Loader>()),
+    mDevice(mLoader->getDevice()) {}
+
+
 
 status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
 {
     ATRACE_CALL();
-    status_t err;
 
-    err = mAllocMod->registerBuffer(mAllocMod, handle);
+    gralloc1_error_t error = mDevice->retain(handle);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
+            handle, error);
 
-    ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
-            handle, err, strerror(-err));
-    return err;
+    return error;
 }
 
-status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
+status_t GraphicBufferMapper::registerBuffer(const GraphicBuffer* buffer)
 {
     ATRACE_CALL();
-    status_t err;
 
-    err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+    gralloc1_error_t error = mDevice->retain(buffer);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
+            buffer->getNativeBuffer()->handle, error);
 
-    ALOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
-            handle, err, strerror(-err));
-    return err;
+    return error;
 }
 
-status_t GraphicBufferMapper::lock(buffer_handle_t handle,
-        uint32_t usage, const Rect& bounds, void** vaddr)
+status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
 {
     ATRACE_CALL();
-    status_t err;
 
-    err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
-            bounds.left, bounds.top, bounds.width(), bounds.height(),
-            vaddr);
+    gralloc1_error_t error = mDevice->release(handle);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "unregisterBuffer(%p): failed %d",
+            handle, error);
 
-    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    return error;
 }
 
-status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle,
-        uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr)
-{
-    ATRACE_CALL();
-    status_t err;
-
-    if (mAllocMod->lock_ycbcr == NULL) {
-        return -EINVAL; // do not log failure
-    }
+static inline gralloc1_rect_t asGralloc1Rect(const Rect& rect) {
+    gralloc1_rect_t outRect{};
+    outRect.left = rect.left;
+    outRect.top = rect.top;
+    outRect.width = rect.width();
+    outRect.height = rect.height();
+    return outRect;
+}
 
-    err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
-            bounds.left, bounds.top, bounds.width(), bounds.height(),
-            ycbcr);
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
+        const Rect& bounds, void** vaddr)
+{
+    return lockAsync(handle, usage, bounds, vaddr, -1);
+}
 
-    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
+        const Rect& bounds, android_ycbcr *ycbcr)
+{
+    return lockAsyncYCbCr(handle, usage, bounds, ycbcr, -1);
 }
 
 status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
 {
-    ATRACE_CALL();
-    status_t err;
-
-    err = mAllocMod->unlock(mAllocMod, handle);
-
-    ALOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    int32_t fenceFd = -1;
+    status_t error = unlockAsync(handle, &fenceFd);
+    if (error == NO_ERROR) {
+        sync_wait(fenceFd, -1);
+        close(fenceFd);
+    }
+    return error;
 }
 
 status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
         uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
 {
     ATRACE_CALL();
-    status_t err;
-
-    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
-        err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage),
-                bounds.left, bounds.top, bounds.width(), bounds.height(),
-                vaddr, fenceFd);
-    } else {
-        if (fenceFd >= 0) {
-            sync_wait(fenceFd, -1);
-            close(fenceFd);
-        }
-        err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
-                bounds.left, bounds.top, bounds.width(), bounds.height(),
-                vaddr);
+
+    gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
+    sp<Fence> fence = new Fence(fenceFd);
+    gralloc1_error_t error = mDevice->lock(handle,
+            static_cast<gralloc1_producer_usage_t>(usage),
+            static_cast<gralloc1_consumer_usage_t>(usage),
+            &accessRegion, vaddr, fence);
+    ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lock(%p, ...) failed: %d", handle,
+            error);
+
+    return error;
+}
+
+static inline bool isValidYCbCrPlane(const android_flex_plane_t& plane) {
+    if (plane.bits_per_component != 8) {
+        ALOGV("Invalid number of bits per component: %d",
+                plane.bits_per_component);
+        return false;
+    }
+    if (plane.bits_used != 8) {
+        ALOGV("Invalid number of bits used: %d", plane.bits_used);
+        return false;
+    }
+
+    bool hasValidIncrement = plane.h_increment == 1 ||
+            (plane.component != FLEX_COMPONENT_Y && plane.h_increment == 2);
+    hasValidIncrement = hasValidIncrement && plane.v_increment > 0;
+    if (!hasValidIncrement) {
+        ALOGV("Invalid increment: h %d v %d", plane.h_increment,
+                plane.v_increment);
+        return false;
     }
 
-    ALOGW_IF(err, "lockAsync(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    return true;
 }
 
 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
         uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
 {
     ATRACE_CALL();
-    status_t err;
-
-    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3
-            && mAllocMod->lockAsync_ycbcr != NULL) {
-        err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle,
-                static_cast<int>(usage), bounds.left, bounds.top,
-                bounds.width(), bounds.height(), ycbcr, fenceFd);
-    } else if (mAllocMod->lock_ycbcr != NULL) {
-        if (fenceFd >= 0) {
-            sync_wait(fenceFd, -1);
-            close(fenceFd);
-        }
-        err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
-                bounds.left, bounds.top, bounds.width(), bounds.height(),
-                ycbcr);
-    } else {
-        if (fenceFd >= 0) {
-            close(fenceFd);
+
+    gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
+    sp<Fence> fence = new Fence(fenceFd);
+
+    if (mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+        gralloc1_error_t error = mDevice->lockYCbCr(handle,
+                static_cast<gralloc1_producer_usage_t>(usage),
+                static_cast<gralloc1_consumer_usage_t>(usage),
+                &accessRegion, ycbcr, fence);
+        ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lockYCbCr(%p, ...) failed: %d",
+                handle, error);
+        return error;
+    }
+
+    uint32_t numPlanes = 0;
+    gralloc1_error_t error = mDevice->getNumFlexPlanes(handle, &numPlanes);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGV("Failed to retrieve number of flex planes: %d", error);
+        return error;
+    }
+    if (numPlanes < 3) {
+        ALOGV("Not enough planes for YCbCr (%u found)", numPlanes);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    std::vector<android_flex_plane_t> planes(numPlanes);
+    android_flex_layout_t flexLayout{};
+    flexLayout.num_planes = numPlanes;
+    flexLayout.planes = planes.data();
+
+    error = mDevice->lockFlex(handle,
+            static_cast<gralloc1_producer_usage_t>(usage),
+            static_cast<gralloc1_consumer_usage_t>(usage),
+            &accessRegion, &flexLayout, fence);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGW("lockFlex(%p, ...) failed: %d", handle, error);
+        return error;
+    }
+    if (flexLayout.format != FLEX_FORMAT_YCbCr) {
+        ALOGV("Unable to convert flex-format buffer to YCbCr");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    // Find planes
+    auto yPlane = planes.cend();
+    auto cbPlane = planes.cend();
+    auto crPlane = planes.cend();
+    for (auto planeIter = planes.cbegin(); planeIter != planes.cend();
+            ++planeIter) {
+        if (planeIter->component == FLEX_COMPONENT_Y) {
+            yPlane = planeIter;
+        } else if (planeIter->component == FLEX_COMPONENT_Cb) {
+            cbPlane = planeIter;
+        } else if (planeIter->component == FLEX_COMPONENT_Cr) {
+            crPlane = planeIter;
         }
-        return -EINVAL; // do not log failure
     }
+    if (yPlane == planes.cend()) {
+        ALOGV("Unable to find Y plane");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (cbPlane == planes.cend()) {
+        ALOGV("Unable to find Cb plane");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (crPlane == planes.cend()) {
+        ALOGV("Unable to find Cr plane");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    // Validate planes
+    if (!isValidYCbCrPlane(*yPlane)) {
+        ALOGV("Y plane is invalid");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (!isValidYCbCrPlane(*cbPlane)) {
+        ALOGV("Cb plane is invalid");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (!isValidYCbCrPlane(*crPlane)) {
+        ALOGV("Cr plane is invalid");
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (cbPlane->v_increment != crPlane->v_increment) {
+        ALOGV("Cb and Cr planes have different step (%d vs. %d)",
+                cbPlane->v_increment, crPlane->v_increment);
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+    if (cbPlane->h_increment != crPlane->h_increment) {
+        ALOGV("Cb and Cr planes have different stride (%d vs. %d)",
+                cbPlane->h_increment, crPlane->h_increment);
+        unlock(handle);
+        return GRALLOC1_ERROR_UNSUPPORTED;
+    }
+
+    // Pack plane data into android_ycbcr struct
+    ycbcr->y = yPlane->top_left;
+    ycbcr->cb = cbPlane->top_left;
+    ycbcr->cr = crPlane->top_left;
+    ycbcr->ystride = static_cast<size_t>(yPlane->v_increment);
+    ycbcr->cstride = static_cast<size_t>(cbPlane->v_increment);
+    ycbcr->chroma_step = static_cast<size_t>(cbPlane->h_increment);
 
-    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    return error;
 }
 
 status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
 {
     ATRACE_CALL();
-    status_t err;
 
-    if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
-        err = mAllocMod->unlockAsync(mAllocMod, handle, fenceFd);
-    } else {
-        *fenceFd = -1;
-        err = mAllocMod->unlock(mAllocMod, handle);
+    sp<Fence> fence = Fence::NO_FENCE;
+    gralloc1_error_t error = mDevice->unlock(handle, &fence);
+    if (error != GRALLOC1_ERROR_NONE) {
+        ALOGE("unlock(%p) failed: %d", handle, error);
+        return error;
     }
 
-    ALOGW_IF(err, "unlockAsync(...) failed %d (%s)", err, strerror(-err));
-    return err;
+    *fenceFd = fence->dup();
+    return error;
 }
 
 // ---------------------------------------------------------------------------
index d23f435..18ef7d5 100644 (file)
@@ -26,7 +26,8 @@
 #endif
 
 #include <private/pixelflinger/ggl_context.h>
-#include <hardware/gralloc.h>
+
+#include <system/window.h>
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -615,7 +616,7 @@ struct ogles_context_t {
     culling_t               cull;
     lighting_t              lighting;
     user_clip_planes_t      clipPlanes;
-    compute_iterators_t     lerp;           __attribute__((aligned(32)));
+    compute_iterators_t     lerp           __attribute__((aligned(32)));
     vertex_t                current;
     vec4_t                  currentColorClamped;
     vec3_t                  currentNormal;
index 92139e9..c1efd1c 100644 (file)
@@ -32,6 +32,7 @@
 #include <utils/threads.h>
 #include <ui/ANativeObjectBase.h>
 #include <ui/Fence.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -242,7 +243,6 @@ private:
     ANativeWindow*   nativeWindow;
     ANativeWindowBuffer*   buffer;
     ANativeWindowBuffer*   previousBuffer;
-    gralloc_module_t const*    module;
     int width;
     int height;
     void* bits;
@@ -341,16 +341,12 @@ egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
         EGLConfig config,
         int32_t depthFormat,
         ANativeWindow* window)
-    : egl_surface_t(dpy, config, depthFormat), 
-    nativeWindow(window), buffer(0), previousBuffer(0), module(0),
-    bits(NULL)
+    : egl_surface_t(dpy, config, depthFormat),
+    nativeWindow(window), buffer(0), previousBuffer(0), bits(NULL)
 {
-    hw_module_t const* pModule;
-    hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
-    module = reinterpret_cast<gralloc_module_t const*>(pModule);
 
     pixelFormatTable = gglGetPixelFormatTable();
-    
+
     // keep a reference on the window
     nativeWindow->common.incRef(&nativeWindow->common);
     nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
@@ -440,22 +436,16 @@ void egl_window_surface_v2_t::disconnect()
 status_t egl_window_surface_v2_t::lock(
         ANativeWindowBuffer* buf, int usage, void** vaddr)
 {
-    int err;
-
-    err = module->lock(module, buf->handle,
-            usage, 0, 0, buf->width, buf->height, vaddr);
-
-    return err;
+    auto& mapper = GraphicBufferMapper::get();
+    return mapper.lock(buf->handle, usage,
+            android::Rect(buf->width, buf->height), vaddr);
 }
 
 status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
 {
     if (!buf) return BAD_VALUE;
-    int err = NO_ERROR;
-
-    err = module->unlock(module, buf->handle);
-
-    return err;
+    auto& mapper = GraphicBufferMapper::get();
+    return mapper.unlock(buf->handle);
 }
 
 void egl_window_surface_v2_t::copyBlt(
index 479bf7e..e7fe9d7 100644 (file)
@@ -229,7 +229,7 @@ static inline void validate_light_mvi(ogles_context_t* c)
 #endif
         vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
     }
-    const vec4_t eyeViewer = { 0, 0, 0x10000, 0 };
+    const vec4_t eyeViewer = {{{ 0, 0, 0x10000, 0 }}};
 #if OBJECT_SPACE_LIGHTING
     c->transforms.mvui.point3(&c->transforms.mvui,
             &c->lighting.objViewer, &eyeViewer);
index cdeccb3..034c857 100644 (file)
@@ -253,13 +253,13 @@ void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rh
 {
     GLfloat const* const m = lhs.m;
     for (int i=0 ; i<4 ; i++) {
-        register const float rhs_i0 = rhs.m[ I(i,0) ];
-        register float ri0 = m[ I(0,0) ] * rhs_i0;
-        register float ri1 = m[ I(0,1) ] * rhs_i0;
-        register float ri2 = m[ I(0,2) ] * rhs_i0;
-        register float ri3 = m[ I(0,3) ] * rhs_i0;
+        const float rhs_i0 = rhs.m[ I(i,0) ];
+        float ri0 = m[ I(0,0) ] * rhs_i0;
+        float ri1 = m[ I(0,1) ] * rhs_i0;
+        float ri2 = m[ I(0,2) ] * rhs_i0;
+        float ri3 = m[ I(0,3) ] * rhs_i0;
         for (int j=1 ; j<4 ; j++) {
-            register const float rhs_ij = rhs.m[ I(i,j) ];
+            const float rhs_ij = rhs.m[ I(i,j) ];
             ri0 += m[ I(j,0) ] * rhs_ij;
             ri1 += m[ I(j,1) ] * rhs_ij;
             ri2 += m[ I(j,2) ] * rhs_ij;
index 9aa1c4f..3fe5ed0 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <ETC1/etc1.h>
 
+#include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -128,17 +131,11 @@ void ogles_lock_textures(ogles_context_t* c)
             ANativeWindowBuffer* native_buffer = u.texture->buffer;
             if (native_buffer) {
                 c->rasterizer.procs.activeTexture(c, i);
-                hw_module_t const* pModule;
-                if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
-                    continue;
-
-                gralloc_module_t const* module =
-                    reinterpret_cast<gralloc_module_t const*>(pModule);
 
+                auto& mapper = GraphicBufferMapper::get();
                 void* vaddr;
-                int err = module->lock(module, native_buffer->handle,
-                        GRALLOC_USAGE_SW_READ_OFTEN,
-                        0, 0, native_buffer->width, native_buffer->height,
+                mapper.lock(native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN,
+                        Rect(native_buffer->width, native_buffer->height),
                         &vaddr);
 
                 u.texture->setImageBits(vaddr);
@@ -156,14 +153,10 @@ void ogles_unlock_textures(ogles_context_t* c)
             ANativeWindowBuffer* native_buffer = u.texture->buffer;
             if (native_buffer) {
                 c->rasterizer.procs.activeTexture(c, i);
-                hw_module_t const* pModule;
-                if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
-                    continue;
 
-                gralloc_module_t const* module =
-                    reinterpret_cast<gralloc_module_t const*>(pModule);
+                auto& mapper = GraphicBufferMapper::get();
+                mapper.unlock(native_buffer->handle);
 
-                module->unlock(module, native_buffer->handle);
                 u.texture->setImageBits(NULL);
                 c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
             }
@@ -405,7 +398,7 @@ int createTextureSurface(ogles_context_t* c,
     return 0;
 }
 
-static size_t dataSizePalette4(int numLevels, int width, int height, int format)
+static GLsizei dataSizePalette4(int numLevels, int width, int height, int format)
 {
     int indexBits = 8;
     int entrySize = 0;
index 374a5de..a2d689b 100644 (file)
@@ -134,6 +134,10 @@ static const int32_t keyCodeRotationMap[][4] = {
         { AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN },
         { AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT },
         { AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP },
+        { AKEYCODE_FP_NAV_DOWN,   AKEYCODE_FP_NAV_RIGHT,  AKEYCODE_FP_NAV_UP,     AKEYCODE_FP_NAV_LEFT },
+        { AKEYCODE_FP_NAV_RIGHT,  AKEYCODE_FP_NAV_UP,     AKEYCODE_FP_NAV_LEFT,   AKEYCODE_FP_NAV_DOWN },
+        { AKEYCODE_FP_NAV_UP,     AKEYCODE_FP_NAV_LEFT,   AKEYCODE_FP_NAV_DOWN,   AKEYCODE_FP_NAV_RIGHT },
+        { AKEYCODE_FP_NAV_LEFT,   AKEYCODE_FP_NAV_DOWN,   AKEYCODE_FP_NAV_RIGHT,  AKEYCODE_FP_NAV_UP },
 };
 static const size_t keyCodeRotationMapSize =
         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
index fb6307e..d654b17 100644 (file)
@@ -44,7 +44,6 @@ LOCAL_C_INCLUDES := \
 
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-#LOCAL_CFLAGS += -DENABLE_FENCE_TRACKING
 
 USE_HWC2 := false
 ifeq ($(USE_HWC2),true)
index 2641ee6..e739ef4 100644 (file)
@@ -2333,7 +2333,7 @@ void HWC2On1Adapter::populateCapabilities()
         int supportedTypes = 0;
         auto result = mHwc1Device->query(mHwc1Device,
                 HWC_DISPLAY_TYPES_SUPPORTED, &supportedTypes);
-        if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL) != 0)) {
+        if ((result == 0) && ((supportedTypes & HWC_DISPLAY_VIRTUAL_BIT) != 0)) {
             ALOGI("Found support for HWC virtual displays");
             mHwc1SupportsVirtualDisplays = true;
         }
index 885d712..0e18a93 100644 (file)
@@ -26,7 +26,9 @@ namespace android {
 FenceTracker::FenceTracker() :
         mFrameCounter(0),
         mOffset(0),
-        mFrames() {}
+        mFrames(),
+        mMutex() {
+}
 
 void FenceTracker::dump(String8* outString) {
     Mutex::Autolock lock(mMutex);
@@ -135,31 +137,30 @@ void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
         nsecs_t postedTime;
         sp<Fence> acquireFence;
         sp<Fence> prevReleaseFence;
-        int32_t key = layers[i]->getSequence();
+        int32_t layerId = layers[i]->getSequence();
 
         layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
                 &postedTime, &acquireFence, &prevReleaseFence);
 #ifdef USE_HWC2
         if (glesComposition) {
             frame.layers.emplace(std::piecewise_construct,
-                    std::forward_as_tuple(key),
+                    std::forward_as_tuple(layerId),
                     std::forward_as_tuple(name, frameNumber, glesComposition,
                     postedTime, 0, 0, acquireFence, prevReleaseFence));
             wasGlesCompositionDone = true;
         } else {
             frame.layers.emplace(std::piecewise_construct,
-                    std::forward_as_tuple(key),
+                    std::forward_as_tuple(layerId),
                     std::forward_as_tuple(name, frameNumber, glesComposition,
                     postedTime, 0, 0, acquireFence, Fence::NO_FENCE));
-
-            auto prevLayer = prevFrame.layers.find(key);
+            auto prevLayer = prevFrame.layers.find(layerId);
             if (prevLayer != prevFrame.layers.end()) {
                 prevLayer->second.releaseFence = prevReleaseFence;
             }
         }
 #else
         frame.layers.emplace(std::piecewise_construct,
-                std::forward_as_tuple(key),
+                std::forward_as_tuple(layerId),
                 std::forward_as_tuple(name, frameNumber, glesComposition,
                 postedTime, 0, 0, acquireFence,
                 glesComposition ? Fence::NO_FENCE : prevReleaseFence));
@@ -168,7 +169,7 @@ void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
         }
 #endif
         frame.layers.emplace(std::piecewise_construct,
-                std::forward_as_tuple(key),
+                std::forward_as_tuple(layerId),
                 std::forward_as_tuple(name, frameNumber, glesComposition,
                 postedTime, 0, 0, acquireFence, prevReleaseFence));
     }
@@ -184,8 +185,35 @@ void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
 
     mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
     mFrameCounter++;
+}
 
+bool FenceTracker::getFrameTimestamps(const Layer& layer,
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+    Mutex::Autolock lock(mMutex);
     checkFencesForCompletion();
+    int32_t layerId = layer.getSequence();
+
+    size_t i = 0;
+    for (; i < MAX_FRAME_HISTORY; i++) {
+       if (mFrames[i].layers.count(layerId) &&
+               mFrames[i].layers[layerId].frameNumber == frameNumber) {
+           break;
+       }
+    }
+    if (i == MAX_FRAME_HISTORY) {
+        return false;
+    }
+
+    const FrameRecord& frameRecord = mFrames[i];
+    const LayerRecord& layerRecord = mFrames[i].layers[layerId];
+    outTimestamps->frameNumber = frameNumber;
+    outTimestamps->postedTime = layerRecord.postedTime;
+    outTimestamps->acquireTime = layerRecord.acquireTime;
+    outTimestamps->refreshStartTime = frameRecord.refreshStartTime;
+    outTimestamps->glCompositionDoneTime = frameRecord.glesCompositionDoneTime;
+    outTimestamps->displayRetireTime = frameRecord.retireTime;
+    outTimestamps->releaseTime = layerRecord.releaseTime;
+    return true;
 }
 
 } // namespace android
index de99820..4cb14a5 100644 (file)
@@ -29,7 +29,7 @@
 namespace android {
 
 class Layer;
-
+struct FrameTimestamps;
 /*
  * Keeps a circular buffer of fence/timestamp data for the last N frames in
  * SurfaceFlinger. Gets timestamps for fences after they have signaled.
@@ -40,9 +40,11 @@ public:
      void dump(String8* outString);
      void addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
              const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence);
+     bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
+             FrameTimestamps* outTimestamps);
 
 protected:
-     static constexpr size_t MAX_FRAME_HISTORY = 128;
+     static constexpr size_t MAX_FRAME_HISTORY = 8;
 
      struct LayerRecord {
          String8 name; // layer name
index 0247723..d732c07 100644 (file)
@@ -155,7 +155,8 @@ void Layer::onFirstRef() {
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
     mProducer = new MonitoredProducer(producer, mFlinger);
-    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
+    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,
+            this);
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mSurfaceFlingerConsumer->setContentsChangedListener(this);
     mSurfaceFlingerConsumer->setName(mName);
@@ -1674,7 +1675,8 @@ bool Layer::onPreComposition() {
     return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
 }
 
-void Layer::onPostComposition() {
+bool Layer::onPostComposition() {
+    bool frameLatencyNeeded = mFrameLatencyNeeded;
     if (mFrameLatencyNeeded) {
         nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
         mFrameTracker.setDesiredPresentTime(desiredPresentTime);
@@ -1706,6 +1708,7 @@ void Layer::onPostComposition() {
         mFrameTracker.advanceFrame();
         mFrameLatencyNeeded = false;
     }
+    return frameLatencyNeeded;
 }
 
 #ifdef USE_HWC2
@@ -2180,6 +2183,20 @@ void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber,
     *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence();
     *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevReleaseFence();
 }
+
+std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
+        bool forceFlush) {
+    std::vector<OccupancyTracker::Segment> history;
+    status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush,
+            &history);
+    if (result != NO_ERROR) {
+        ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(),
+                result);
+        return {};
+    }
+    return history;
+}
+
 // ---------------------------------------------------------------------------
 
 Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
index ba7184f..4257c37 100644 (file)
@@ -274,9 +274,10 @@ public:
     bool onPreComposition();
 
     /*
-     *  called after composition.
+     * called after composition.
+     * returns true if the layer latched a new buffer this frame.
      */
-    void onPostComposition();
+    bool onPostComposition();
 
 #ifdef USE_HWC2
     // If a buffer was replaced this frame, release the former buffer
@@ -406,6 +407,13 @@ public:
             bool* outIsGlesComposition, nsecs_t* outPostedTime,
             sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const;
 
+    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
+
+    bool getFrameTimestamps(uint64_t frameNumber,
+            FrameTimestamps* outTimestamps) const {
+        return mFlinger->getFrameTimestamps(*this, frameNumber, outTimestamps);
+    }
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
index a10a813..9f357df 100644 (file)
@@ -939,11 +939,7 @@ bool SurfaceFlinger::handleMessageInvalidate() {
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
-#ifdef ENABLE_FENCE_TRACKING
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#else
-    nsecs_t refreshStartTime = 0;
-#endif
     static nsecs_t previousExpectedPresent = 0;
     nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
     static bool previousFrameMissed = false;
@@ -1033,11 +1029,7 @@ void SurfaceFlinger::preComposition()
     }
 }
 
-#ifdef ENABLE_FENCE_TRACKING
 void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
-#else
-void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
-#endif
 {
     ATRACE_CALL();
     ALOGV("postComposition");
@@ -1045,7 +1037,11 @@ void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        layers[i]->onPostComposition();
+        bool frameLatched = layers[i]->onPostComposition();
+        if (frameLatched) {
+            recordBufferingStats(layers[i]->getName().string(),
+                    layers[i]->getOccupancyHistory(false));
+        }
     }
 
     sp<Fence> presentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
@@ -1065,10 +1061,8 @@ void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
         }
     }
 
-#ifdef ENABLE_FENCE_TRACKING
     mFenceTracker.addFrame(refreshStartTime, presentFence,
             hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
-#endif
 
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
@@ -1646,6 +1640,8 @@ void SurfaceFlinger::commitTransaction()
     if (!mLayersPendingRemoval.isEmpty()) {
         // Notify removed layers now that they can't be drawn from
         for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
+            recordBufferingStats(mLayersPendingRemoval[i]->getName().string(),
+                    mLayersPendingRemoval[i]->getOccupancyHistory(true));
             mLayersPendingRemoval[i]->onRemoved();
         }
         mLayersPendingRemoval.clear();
@@ -2607,14 +2603,12 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
                 dumpAll = false;
             }
 
-#ifdef ENABLE_FENCE_TRACKING
             if ((index < numArgs) &&
                     (args[index] == String16("--fences"))) {
                 index++;
                 mFenceTracker.dump(&result);
                 dumpAll = false;
             }
-#endif
         }
 
         if (dumpAll) {
@@ -2735,6 +2729,59 @@ void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
             NUM_BUCKETS - 1, bucketTimeSec, percent);
 }
 
+void SurfaceFlinger::recordBufferingStats(const char* layerName,
+        std::vector<OccupancyTracker::Segment>&& history) {
+    Mutex::Autolock lock(mBufferingStatsMutex);
+    auto& stats = mBufferingStats[layerName];
+    for (const auto& segment : history) {
+        if (!segment.usedThirdBuffer) {
+            stats.twoBufferTime += segment.totalTime;
+        }
+        if (segment.occupancyAverage < 1.0f) {
+            stats.doubleBufferedTime += segment.totalTime;
+        } else if (segment.occupancyAverage < 2.0f) {
+            stats.tripleBufferedTime += segment.totalTime;
+        }
+        ++stats.numSegments;
+        stats.totalTime += segment.totalTime;
+    }
+}
+
+void SurfaceFlinger::dumpBufferingStats(String8& result) const {
+    result.append("Buffering stats:\n");
+    result.append("  [Layer name] <Active time> <Two buffer> "
+            "<Double buffered> <Triple buffered>\n");
+    Mutex::Autolock lock(mBufferingStatsMutex);
+    typedef std::tuple<std::string, float, float, float> BufferTuple;
+    std::map<float, BufferTuple, std::greater<float>> sorted;
+    for (const auto& statsPair : mBufferingStats) {
+        const char* name = statsPair.first.c_str();
+        const BufferingStats& stats = statsPair.second;
+        if (stats.numSegments == 0) {
+            continue;
+        }
+        float activeTime = ns2ms(stats.totalTime) / 1000.0f;
+        float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
+                stats.totalTime;
+        float doubleBufferRatio = static_cast<float>(
+                stats.doubleBufferedTime) / stats.totalTime;
+        float tripleBufferRatio = static_cast<float>(
+                stats.tripleBufferedTime) / stats.totalTime;
+        sorted.insert({activeTime, {name, twoBufferRatio,
+                doubleBufferRatio, tripleBufferRatio}});
+    }
+    for (const auto& sortedPair : sorted) {
+        float activeTime = sortedPair.first;
+        const BufferTuple& values = sortedPair.second;
+        result.appendFormat("  [%s] %.2f %.3f %.3f %.3f\n",
+                std::get<0>(values).c_str(), activeTime,
+                std::get<1>(values), std::get<2>(values),
+                std::get<3>(values));
+    }
+    result.append("\n");
+}
+
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -2788,6 +2835,8 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
     dumpStaticScreenStats(result);
     result.append("\n");
 
+    dumpBufferingStats(result);
+
     /*
      * Dump the visible layer list
      */
@@ -3560,6 +3609,11 @@ void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* v
     }
 }
 
+bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+    return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
+}
+
 // ---------------------------------------------------------------------------
 
 SurfaceFlinger::LayerVector::LayerVector() {
index 633e956..28666e2 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/OccupancyTracker.h>
 
 #include <hardware/hwcomposer_defs.h>
 
@@ -57,6 +58,9 @@
 #include "DisplayHardware/HWComposer.h"
 #include "Effects/Daltonizer.h"
 
+#include <map>
+#include <string>
+
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -432,6 +436,13 @@ private:
 
     void dumpStaticScreenStats(String8& result) const;
 
+    void recordBufferingStats(const char* layerName,
+            std::vector<OccupancyTracker::Segment>&& history);
+    void dumpBufferingStats(String8& result) const;
+
+    bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
+            FrameTimestamps* outTimestamps);
+
     /* ------------------------------------------------------------------------
      * Attributes
      */
@@ -526,6 +537,29 @@ private:
     nsecs_t mFrameBuckets[NUM_BUCKETS];
     nsecs_t mTotalTime;
     std::atomic<nsecs_t> mLastSwapTime;
+
+    // Double- vs. triple-buffering stats
+    struct BufferingStats {
+        BufferingStats()
+          : numSegments(0),
+            totalTime(0),
+            twoBufferTime(0),
+            doubleBufferedTime(0),
+            tripleBufferedTime(0) {}
+
+        size_t numSegments;
+        nsecs_t totalTime;
+
+        // "Two buffer" means that a third buffer was never used, whereas
+        // "double-buffered" means that on average the segment only used two
+        // buffers (though it may have used a third for some part of the
+        // segment)
+        nsecs_t twoBufferTime;
+        nsecs_t doubleBufferedTime;
+        nsecs_t tripleBufferedTime;
+    };
+    mutable Mutex mBufferingStatsMutex;
+    std::unordered_map<std::string, BufferingStats> mBufferingStats;
 };
 
 }; // namespace android
index c71b3bc..ba0a527 100644 (file)
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include "SurfaceFlingerConsumer.h"
+#include "Layer.h"
 
 #include <private/gui/SyncFeatures.h>
 
@@ -251,6 +252,12 @@ void SurfaceFlingerConsumer::onSidebandStreamChanged() {
     }
 }
 
+bool SurfaceFlingerConsumer::getFrameTimestamps(uint64_t frameNumber,
+        FrameTimestamps* outTimestamps) const {
+    sp<const Layer> l = mLayer.promote();
+    return l.get() ? l->getFrameTimestamps(frameNumber, outTimestamps) : false;
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 
index 51b002f..3762659 100644 (file)
@@ -23,6 +23,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class Layer;
+
 /*
  * This is a thin wrapper around GLConsumer.
  */
@@ -35,10 +37,10 @@ public:
     };
 
     SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
-            uint32_t tex)
+            uint32_t tex, const Layer* layer)
         : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
           mTransformToDisplayInverse(false), mSurfaceDamage(),
-          mPrevReleaseFence(Fence::NO_FENCE)
+          mPrevReleaseFence(Fence::NO_FENCE), mLayer(layer)
     {}
 
     class BufferRejecter {
@@ -82,6 +84,9 @@ public:
     void releasePendingBuffer();
 #endif
 
+    virtual bool getFrameTimestamps(uint64_t frameNumber,
+            FrameTimestamps* outTimestamps) const override;
+
 private:
     virtual void onSidebandStreamChanged();
 
@@ -103,6 +108,9 @@ private:
 
     // The release fence of the already displayed buffer (previous frame).
     sp<Fence> mPrevReleaseFence;
+
+    // The layer for this SurfaceFlingerConsumer
+    wp<const Layer> mLayer;
 };
 
 // ----------------------------------------------------------------------------
index 7f3b269..a86c692 100644 (file)
@@ -943,11 +943,7 @@ bool SurfaceFlinger::handleMessageInvalidate() {
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
-#ifdef ENABLE_FENCE_TRACKING
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#else
-    nsecs_t refreshStartTime = 0;
-#endif
     static nsecs_t previousExpectedPresent = 0;
     nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
     static bool previousFrameMissed = false;
@@ -1029,16 +1025,16 @@ void SurfaceFlinger::preComposition()
     }
 }
 
-#ifdef ENABLE_FENCE_TRACKING
 void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
-#else
-void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
-#endif
 {
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        layers[i]->onPostComposition();
+        bool frameLatched = layers[i]->onPostComposition();
+        if (frameLatched) {
+            recordBufferingStats(layers[i]->getName().string(),
+                    layers[i]->getOccupancyHistory(false));
+        }
     }
 
     const HWComposer& hwc = getHwComposer();
@@ -1059,10 +1055,8 @@ void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
         }
     }
 
-#ifdef ENABLE_FENCE_TRACKING
     mFenceTracker.addFrame(refreshStartTime, presentFence,
             hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
-#endif
 
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
@@ -1666,6 +1660,8 @@ void SurfaceFlinger::commitTransaction()
     if (!mLayersPendingRemoval.isEmpty()) {
         // Notify removed layers now that they can't be drawn from
         for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
+            recordBufferingStats(mLayersPendingRemoval[i]->getName().string(),
+                    mLayersPendingRemoval[i]->getOccupancyHistory(true));
             mLayersPendingRemoval[i]->onRemoved();
         }
         mLayersPendingRemoval.clear();
@@ -2623,14 +2619,12 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
                 dumpAll = false;
             }
 
-#ifdef ENABLE_FENCE_TRACKING
             if ((index < numArgs) &&
                     (args[index] == String16("--fences"))) {
                 index++;
                 mFenceTracker.dump(&result);
                 dumpAll = false;
             }
-#endif
         }
 
         if (dumpAll) {
@@ -2751,6 +2745,58 @@ void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
             NUM_BUCKETS - 1, bucketTimeSec, percent);
 }
 
+void SurfaceFlinger::recordBufferingStats(const char* layerName,
+        std::vector<OccupancyTracker::Segment>&& history) {
+    Mutex::Autolock lock(mBufferingStatsMutex);
+    auto& stats = mBufferingStats[layerName];
+    for (const auto& segment : history) {
+        if (!segment.usedThirdBuffer) {
+            stats.twoBufferTime += segment.totalTime;
+        }
+        if (segment.occupancyAverage < 1.0f) {
+            stats.doubleBufferedTime += segment.totalTime;
+        } else if (segment.occupancyAverage < 2.0f) {
+            stats.tripleBufferedTime += segment.totalTime;
+        }
+        ++stats.numSegments;
+        stats.totalTime += segment.totalTime;
+    }
+}
+
+void SurfaceFlinger::dumpBufferingStats(String8& result) const {
+    result.append("Buffering stats:\n");
+    result.append("  [Layer name] <Active time> <Two buffer> "
+            "<Double buffered> <Triple buffered>\n");
+    Mutex::Autolock lock(mBufferingStatsMutex);
+    typedef std::tuple<std::string, float, float, float> BufferTuple;
+    std::map<float, BufferTuple, std::greater<float>> sorted;
+    for (const auto& statsPair : mBufferingStats) {
+        const char* name = statsPair.first.c_str();
+        const BufferingStats& stats = statsPair.second;
+        if (stats.numSegments == 0) {
+            continue;
+        }
+        float activeTime = ns2ms(stats.totalTime) / 1000.0f;
+        float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
+                stats.totalTime;
+        float doubleBufferRatio = static_cast<float>(
+                stats.doubleBufferedTime) / stats.totalTime;
+        float tripleBufferRatio = static_cast<float>(
+                stats.tripleBufferedTime) / stats.totalTime;
+        sorted.insert({activeTime, {name, twoBufferRatio,
+                doubleBufferRatio, tripleBufferRatio}});
+    }
+    for (const auto& sortedPair : sorted) {
+        float activeTime = sortedPair.first;
+        const BufferTuple& values = sortedPair.second;
+        result.appendFormat("  [%s] %.2f %.3f %.3f %.3f\n",
+                std::get<0>(values).c_str(), activeTime,
+                std::get<1>(values), std::get<2>(values),
+                std::get<3>(values));
+    }
+    result.append("\n");
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -2802,6 +2848,8 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
     dumpStaticScreenStats(result);
     result.append("\n");
 
+    dumpBufferingStats(result);
+
     /*
      * Dump the visible layer list
      */
@@ -3548,6 +3596,11 @@ status_t SurfaceFlinger::captureScreenImplLocked(
     return result;
 }
 
+bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
+        uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+    return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
+}
+
 void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
         const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
     if (DEBUG_SCREENSHOTS) {
index 2b4ea2a..435aa0c 100644 (file)
@@ -3,4 +3,4 @@ service surfaceflinger /system/bin/surfaceflinger
     user system
     group graphics drmrpc readproc
     onrestart restart zygote
-    writepid /sys/fs/cgroup/stune/foreground/tasks
+    writepid /dev/stune/foreground/tasks