Merge "libs: add libpackagelistparser"
am: cc7373eafd
* commit 'cc7373eafd0d5be7df8898748a700b47298ebf10':
libs: add libpackagelistparser
diff --git a/libs/packagelistparser/Android.mk b/libs/packagelistparser/Android.mk
new file mode 100644
index 0000000..802a3cb
--- /dev/null
+++ b/libs/packagelistparser/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+#########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libpackagelistparser
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := packagelistparser.c
+LOCAL_COPY_HEADERS_TO := packagelistparser
+LOCAL_COPY_HEADERS := packagelistparser.h
+LOCAL_SHARED_LIBRARIES := liblog
+
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+
+include $(BUILD_SHARED_LIBRARY)
+
+#########################
+include $(CLEAR_VARS)
+
+
+LOCAL_MODULE := libpackagelistparser
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := packagelistparser.c
+LOCAL_COPY_HEADERS_TO := packagelistparser
+LOCAL_COPY_HEADERS := packagelistparser.h
+LOCAL_STATIC_LIBRARIES := liblog
+
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/packagelistparser/packagelistparser.c b/libs/packagelistparser/packagelistparser.c
new file mode 100644
index 0000000..3e2539c
--- /dev/null
+++ b/libs/packagelistparser/packagelistparser.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2015, Intel Corporation
+ * 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.
+ *
+ * Written by William Roberts <william.c.roberts@intel.com>
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/limits.h>
+
+#define LOG_TAG "packagelistparser"
+#include <utils/Log.h>
+
+#include "packagelistparser.h"
+
+#define CLOGE(fmt, ...) \
+ do {\
+ IF_ALOGE() {\
+ ALOGE(fmt, ##__VA_ARGS__);\
+ }\
+ } while(0)
+
+static size_t get_gid_cnt(const char *gids)
+{
+ size_t cnt;
+
+ if (*gids == '\0') {
+ return 0;
+ }
+
+ if (!strcmp(gids, "none")) {
+ return 0;
+ }
+
+ for (cnt = 1; gids[cnt]; gids[cnt] == ',' ? cnt++ : *gids++)
+ ;
+
+ return cnt;
+}
+
+static bool parse_gids(char *gids, gid_t *gid_list, size_t *cnt)
+{
+ gid_t gid;
+ char* token;
+ char *endptr;
+ size_t cmp = 0;
+
+ while ((token = strsep(&gids, ",\r\n"))) {
+
+ if (cmp > *cnt) {
+ return false;
+ }
+
+ gid = strtoul(token, &endptr, 10);
+ if (*endptr != '\0') {
+ return false;
+ }
+
+ /*
+ * if unsigned long is greater than size of gid_t,
+ * prevent a truncation based roll-over
+ */
+ if (gid > GID_MAX) {
+ CLOGE("A gid in field \"gid list\" greater than GID_MAX");
+ return false;
+ }
+
+ gid_list[cmp++] = gid;
+ }
+ return true;
+}
+
+extern bool packagelist_parse(pfn_on_package callback, void *userdata)
+{
+
+ FILE *fp;
+ char *cur;
+ char *next;
+ char *endptr;
+ unsigned long tmp;
+ ssize_t bytesread;
+
+ bool rc = false;
+ char *buf = NULL;
+ size_t buflen = 0;
+ unsigned long lineno = 1;
+ const char *errmsg = NULL;
+ struct pkg_info *pkg_info = NULL;
+
+ fp = fopen(PACKAGES_LIST_FILE, "re");
+ if (!fp) {
+ CLOGE("Could not open: \"%s\", error: \"%s\"\n", PACKAGES_LIST_FILE,
+ strerror(errno));
+ return false;
+ }
+
+ while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
+
+ pkg_info = calloc(1, sizeof(*pkg_info));
+ if (!pkg_info) {
+ goto err;
+ }
+
+ next = buf;
+
+ cur = strsep(&next, " \t\r\n");
+ if (!cur) {
+ errmsg = "Could not get next token for \"package name\"";
+ goto err;
+ }
+
+ pkg_info->name = strdup(cur);
+ if (!pkg_info->name) {
+ goto err;
+ }
+
+ cur = strsep(&next, " \t\r\n");
+ if (!cur) {
+ errmsg = "Could not get next token for field \"uid\"";
+ goto err;
+ }
+
+ tmp = strtoul(cur, &endptr, 10);
+ if (*endptr != '\0') {
+ errmsg = "Could not convert field \"uid\" to integer value";
+ goto err;
+ }
+
+ /*
+ * if unsigned long is greater than size of uid_t,
+ * prevent a truncation based roll-over
+ */
+ if (tmp > UID_MAX) {
+ errmsg = "Field \"uid\" greater than UID_MAX";
+ goto err;
+ }
+
+ pkg_info->uid = (uid_t) tmp;
+
+ cur = strsep(&next, " \t\r\n");
+ if (!cur) {
+ errmsg = "Could not get next token for field \"debuggable\"";
+ goto err;
+ }
+
+ tmp = strtoul(cur, &endptr, 10);
+ if (*endptr != '\0') {
+ errmsg = "Could not convert field \"debuggable\" to integer value";
+ goto err;
+ }
+
+ /* should be a valid boolean of 1 or 0 */
+ if (!(tmp == 0 || tmp == 1)) {
+ errmsg = "Field \"debuggable\" is not 0 or 1 boolean value";
+ goto err;
+ }
+
+ pkg_info->debuggable = (bool) tmp;
+
+ cur = strsep(&next, " \t\r\n");
+ if (!cur) {
+ errmsg = "Could not get next token for field \"data dir\"";
+ goto err;
+ }
+
+ pkg_info->data_dir = strdup(cur);
+ if (!pkg_info->data_dir) {
+ goto err;
+ }
+
+ cur = strsep(&next, " \t\r\n");
+ if (!cur) {
+ errmsg = "Could not get next token for field \"seinfo\"";
+ goto err;
+ }
+
+ pkg_info->seinfo = strdup(cur);
+ if (!pkg_info->seinfo) {
+ goto err;
+ }
+
+ cur = strsep(&next, " \t\r\n");
+ if (!cur) {
+ errmsg = "Could not get next token for field \"gid(s)\"";
+ goto err;
+ }
+
+ /*
+ * Parse the gid list, could be in the form of none, single gid or list:
+ * none
+ * gid
+ * gid, gid ...
+ */
+ pkg_info->gids.cnt = get_gid_cnt(cur);
+ if (pkg_info->gids.cnt > 0) {
+
+ pkg_info->gids.gids = calloc(pkg_info->gids.cnt, sizeof(gid_t));
+ if (!pkg_info->gids.gids) {
+ goto err;
+ }
+
+ rc = parse_gids(cur, pkg_info->gids.gids, &pkg_info->gids.cnt);
+ if (!rc) {
+ errmsg = "Could not parse field \"gid list\"";
+ goto err;
+ }
+ }
+
+ rc = callback(pkg_info, userdata);
+ if (rc == false) {
+ /*
+ * We do not log this as this can be intentional from
+ * callback to abort processing. We go to out to not
+ * free the pkg_info
+ */
+ rc = true;
+ goto out;
+ }
+ lineno++;
+ }
+
+ rc = true;
+
+out:
+ free(buf);
+ fclose(fp);
+ return rc;
+
+err:
+ if (errmsg) {
+ CLOGE("Error Parsing \"%s\" on line: %lu for reason: %s",
+ PACKAGES_LIST_FILE, lineno, errmsg);
+ }
+ rc = false;
+ packagelist_free(pkg_info);
+ goto out;
+}
+
+void packagelist_free(pkg_info *info)
+{
+ if (info) {
+ free(info->name);
+ free(info->data_dir);
+ free(info->seinfo);
+ free(info->gids.gids);
+ free(info);
+ }
+}
diff --git a/libs/packagelistparser/packagelistparser.h b/libs/packagelistparser/packagelistparser.h
new file mode 100644
index 0000000..d602c26
--- /dev/null
+++ b/libs/packagelistparser/packagelistparser.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015, Intel Corporation
+ * 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.
+ *
+ * Written by William Roberts <william.c.roberts@intel.com>
+ *
+ * This is a parser library for parsing the packages.list file generated
+ * by PackageManager service.
+ *
+ * This simple parser is sensitive to format changes in
+ * frameworks/base/services/core/java/com/android/server/pm/Settings.java
+ * A dependency note has been added to that file to correct
+ * this parser.
+ */
+
+#ifndef PACKAGELISTPARSER_H_
+#define PACKAGELISTPARSER_H_
+
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+/** The file containing the list of installed packages on the system */
+#define PACKAGES_LIST_FILE "/data/system/packages.list"
+
+typedef struct pkg_info pkg_info;
+typedef struct gid_list gid_list;
+
+struct gid_list {
+ size_t cnt;
+ gid_t *gids;
+};
+
+struct pkg_info {
+ char *name;
+ uid_t uid;
+ bool debuggable;
+ char *data_dir;
+ char *seinfo;
+ gid_list gids;
+ void *private_data;
+};
+
+/**
+ * Callback function to be used by packagelist_parse() routine.
+ * @param info
+ * The parsed package information
+ * @param userdata
+ * The supplied userdata pointer to packagelist_parse()
+ * @return
+ * true to keep processing, false to stop.
+ */
+typedef bool (*pfn_on_package)(pkg_info *info, void *userdata);
+
+/**
+ * Parses the file specified by PACKAGES_LIST_FILE and invokes the callback on
+ * each entry found. Once the callback is invoked, ownership of the pkg_info pointer
+ * is passed to the callback routine, thus they are required to perform any cleanup
+ * desired.
+ * @param callback
+ * The callback function called on each parsed line of the packages list.
+ * @param userdata
+ * An optional userdata supplied pointer to pass to the callback function.
+ * @return
+ * true on success false on failure.
+ */
+extern bool packagelist_parse(pfn_on_package callback, void *userdata);
+
+/**
+ * Frees a pkg_info structure.
+ * @param info
+ * The struct to free
+ */
+extern void packagelist_free(pkg_info *info);
+
+__END_DECLS
+
+#endif /* PACKAGELISTPARSER_H_ */
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 943e649..571be0e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2267,10 +2267,8 @@
//
// DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
- // system/core/logd/LogStatistics.cpp
+ // frameworks/base/libs/packagelistparser
// system/core/run-as/run-as.c
- // system/core/sdcard/sdcard.c
- // external/libselinux/src/android.c:package_info_init()
//
sb.setLength(0);
sb.append(ai.packageName);