Merge "fs_mgr: adb-remount-test: non-verity recovery"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 66d0c92..a3bd44f 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -19,6 +19,9 @@
"name": "libbase_test"
},
{
+ "name": "libpackagelistparser_test"
+ },
+ {
"name": "libprocinfo_test"
},
{
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 6372b3d..dc2525c 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -688,7 +688,7 @@
android::base::SystemErrorCodeToString(err).c_str());
}
_socket_set_errno(err);
- result = -1;
+ return -1;
}
CHECK_GE(static_cast<DWORD>(std::numeric_limits<int>::max()), bytes_written);
return static_cast<int>(bytes_written);
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
index cbbd8c9..10efaa3 100644
--- a/base/include/android-base/endian.h
+++ b/base/include/android-base/endian.h
@@ -41,23 +41,28 @@
#else
-/* Mac OS and Windows have nothing. */
-
-#define __LITTLE_ENDIAN 1234
+#if defined(__APPLE__)
+/* macOS has some of the basics. */
+#include <sys/_endian.h>
+#else
+/* Windows really has nothing. */
#define LITTLE_ENDIAN __LITTLE_ENDIAN
-
-#define __BIG_ENDIAN 4321
#define BIG_ENDIAN __BIG_ENDIAN
-
-#define __BYTE_ORDER __LITTLE_ENDIAN
#define BYTE_ORDER __BYTE_ORDER
-
#define htons(x) __builtin_bswap16(x)
#define htonl(x) __builtin_bswap32(x)
-#define htonq(x) __builtin_bswap64(x)
-
#define ntohs(x) __builtin_bswap16(x)
#define ntohl(x) __builtin_bswap32(x)
+#endif
+
+/* Neither macOS nor Windows have the rest. */
+
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#define htonq(x) __builtin_bswap64(x)
+
#define ntohq(x) __builtin_bswap64(x)
#define htobe16(x) __builtin_bswap16(x)
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index dcee6d2d..8dbe955 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -18,6 +18,7 @@
#include <stddef.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <functional>
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index bffcb7e..8a983ad 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -17,6 +17,7 @@
#include "writer.h"
#include <inttypes.h>
+#include <string.h>
#include <unistd.h>
#include <string>
diff --git a/init/action.cpp b/init/action.cpp
index 1a66eee..69e40d0 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -195,10 +195,11 @@
found = true;
}
} else {
- std::string prop_val = android::base::GetProperty(trigger_name, "");
- if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) {
- return false;
+ std::string prop_value = android::base::GetProperty(trigger_name, "");
+ if (trigger_value == "*" && !prop_value.empty()) {
+ continue;
}
+ if (trigger_value != prop_value) return false;
}
}
return found;
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 5144fc6..b9420d4 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -67,7 +67,6 @@
"native_handle.cpp",
"record_stream.cpp",
"sockets.cpp",
- "strdup16to8.cpp",
"strlcpy.c",
"threads.cpp",
],
diff --git a/libcutils/include/cutils/jstring.h b/libcutils/include/cutils/jstring.h
deleted file mode 100644
index 6ede786..0000000
--- a/libcutils/include/cutils/jstring.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if __STDC_VERSION__ < 201112L && __cplusplus < 201103L
- typedef uint16_t char16_t;
-#endif
- // otherwise char16_t is a keyword with the right semantics
-
-extern char * strndup16to8 (const char16_t* s, size_t n);
-extern size_t strnlen16to8 (const char16_t* s, size_t n);
-extern char * strncpy16to8 (char *dest, const char16_t*s, size_t n);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/libcutils/include_vndk/cutils/jstring.h b/libcutils/include_vndk/cutils/jstring.h
deleted file mode 120000
index f3fd546..0000000
--- a/libcutils/include_vndk/cutils/jstring.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/jstring.h
\ No newline at end of file
diff --git a/libcutils/strdup16to8.cpp b/libcutils/strdup16to8.cpp
deleted file mode 100644
index d89181e..0000000
--- a/libcutils/strdup16to8.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/* libs/cutils/strdup16to8.c
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <cutils/jstring.h>
-
-#include <assert.h>
-#include <limits.h> /* for SIZE_MAX */
-#include <stdlib.h>
-
-
-/**
- * Given a UTF-16 string, compute the length of the corresponding UTF-8
- * string in bytes.
- */
-extern size_t strnlen16to8(const char16_t* utf16Str, size_t len)
-{
- size_t utf8Len = 0;
-
- /* A small note on integer overflow. The result can
- * potentially be as big as 3*len, which will overflow
- * for len > SIZE_MAX/3.
- *
- * Moreover, the result of a strnlen16to8 is typically used
- * to allocate a destination buffer to strncpy16to8 which
- * requires one more byte to terminate the UTF-8 copy, and
- * this is generally done by careless users by incrementing
- * the result without checking for integer overflows, e.g.:
- *
- * dst = malloc(strnlen16to8(utf16,len)+1)
- *
- * Due to this, the following code will try to detect
- * overflows, and never return more than (SIZE_MAX-1)
- * when it detects one. A careless user will try to malloc
- * SIZE_MAX bytes, which will return NULL which can at least
- * be detected appropriately.
- *
- * As far as I know, this function is only used by strndup16(),
- * but better be safe than sorry.
- */
-
- /* Fast path for the usual case where 3*len is < SIZE_MAX-1.
- */
- if (len < (SIZE_MAX-1)/3) {
- while (len != 0) {
- len--;
- unsigned int uic = *utf16Str++;
-
- if (uic > 0x07ff)
- utf8Len += 3;
- else if (uic > 0x7f || uic == 0)
- utf8Len += 2;
- else
- utf8Len++;
- }
- return utf8Len;
- }
-
- /* The slower but paranoid version */
- while (len != 0) {
- len--;
- unsigned int uic = *utf16Str++;
- size_t utf8Cur = utf8Len;
-
- if (uic > 0x07ff)
- utf8Len += 3;
- else if (uic > 0x7f || uic == 0)
- utf8Len += 2;
- else
- utf8Len++;
-
- if (utf8Len < utf8Cur) /* overflow detected */
- return SIZE_MAX-1;
- }
-
- /* don't return SIZE_MAX to avoid common user bug */
- if (utf8Len == SIZE_MAX)
- utf8Len = SIZE_MAX-1;
-
- return utf8Len;
-}
-
-
-/**
- * Convert a Java-Style UTF-16 string + length to a JNI-Style UTF-8 string.
- *
- * This basically means: embedded \0's in the UTF-16 string are encoded
- * as "0xc0 0x80"
- *
- * Make sure you allocate "utf8Str" with the result of strlen16to8() + 1,
- * not just "len".
- *
- * Please note, a terminated \0 is always added, so your result will always
- * be "strlen16to8() + 1" bytes long.
- */
-extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len)
-{
- char* utf8cur = utf8Str;
-
- /* Note on overflows: We assume the user did check the result of
- * strnlen16to8() properly or at a minimum checked the result of
- * its malloc(SIZE_MAX) in case of overflow.
- */
- while (len != 0) {
- len--;
- unsigned int uic = *utf16Str++;
-
- if (uic > 0x07ff) {
- *utf8cur++ = (uic >> 12) | 0xe0;
- *utf8cur++ = ((uic >> 6) & 0x3f) | 0x80;
- *utf8cur++ = (uic & 0x3f) | 0x80;
- } else if (uic > 0x7f || uic == 0) {
- *utf8cur++ = (uic >> 6) | 0xc0;
- *utf8cur++ = (uic & 0x3f) | 0x80;
- } else {
- *utf8cur++ = uic;
-
- if (uic == 0) {
- break;
- }
- }
- }
-
- *utf8cur = '\0';
-
- return utf8Str;
-}
-
-/**
- * Convert a UTF-16 string to UTF-8.
- *
- */
-char * strndup16to8 (const char16_t* s, size_t n)
-{
- if (s == NULL) {
- return NULL;
- }
-
- size_t len = strnlen16to8(s, n);
-
- /* We are paranoid, and we check for SIZE_MAX-1
- * too since it is an overflow value for our
- * strnlen16to8 implementation.
- */
- if (len >= SIZE_MAX-1)
- return NULL;
-
- char* ret = static_cast<char*>(malloc(len + 1));
- if (ret == NULL)
- return NULL;
-
- strncpy16to8 (ret, s, n);
-
- return ret;
-}
diff --git a/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp b/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
index eb53e57..7bba599 100644
--- a/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
+++ b/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
@@ -17,6 +17,7 @@
#include <inttypes.h>
#include <linux/dma-buf.h>
#include <poll.h>
+#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
@@ -230,7 +231,7 @@
DmaBufTester() : ion_fd(ion_open()), ion_heap_mask(get_ion_heap_mask()) {}
~DmaBufTester() {
- if (is_valid()) {
+ if (ion_fd >= 0) {
ion_close(ion_fd);
}
}
@@ -241,12 +242,16 @@
int fd;
int err = ion_alloc_fd(ion_fd, size, 0, ion_heap_mask, 0, &fd);
if (err < 0) {
- return unique_fd{err};
+ printf("Failed ion_alloc_fd, return value: %d\n", err);
+ return unique_fd{};
}
if (!name.empty()) {
- err = ioctl(fd, DMA_BUF_SET_NAME, name.c_str());
- if (err < 0) return unique_fd{-errno};
+ if (ioctl(fd, DMA_BUF_SET_NAME, name.c_str()) == -1) {
+ printf("Failed ioctl(DMA_BUF_SET_NAME): %s\n", strerror(errno));
+ close(fd);
+ return unique_fd{};
+ }
}
return unique_fd{fd};
@@ -306,7 +311,7 @@
return ret;
}
- unique_fd ion_fd;
+ int ion_fd;
const int ion_heap_mask;
};
diff --git a/libpackagelistparser/.clang-format b/libpackagelistparser/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libpackagelistparser/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index c38594a..0740e7d 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -1,12 +1,7 @@
cc_library {
-
name: "libpackagelistparser",
recovery_available: true,
- srcs: ["packagelistparser.c"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
+ srcs: ["packagelistparser.cpp"],
shared_libs: ["liblog"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
@@ -15,3 +10,13 @@
misc_undefined: ["integer"],
},
}
+
+cc_test {
+ name: "libpackagelistparser_test",
+ srcs: ["packagelistparser_test.cpp"],
+ shared_libs: [
+ "libbase",
+ "libpackagelistparser",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h
index 3cb6b9a..e89cb54 100644
--- a/libpackagelistparser/include/packagelistparser/packagelistparser.h
+++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h
@@ -1,94 +1,81 @@
/*
- * Copyright 2015, Intel Corporation
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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
+ * 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_
+#pragma once
#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 gid_list {
+ /** Number of gids. */
+ size_t cnt;
-typedef struct pkg_info pkg_info;
-typedef struct gid_list gid_list;
+ /** Array of gids. */
+ gid_t* gids;
+} gid_list;
-struct gid_list {
- size_t cnt;
- gid_t *gids;
-};
+typedef struct pkg_info {
+ /** Package name like "com.android.blah". */
+ char* name;
-struct pkg_info {
- char *name;
- uid_t uid;
- bool debuggable;
- char *data_dir;
- char *seinfo;
- gid_list gids;
- void *private_data;
- bool profileable_from_shell;
- long version_code;
-};
+ /** Package uid like 10014. */
+ uid_t uid;
+
+ /** Package's AndroidManifest.xml debuggable flag. */
+ bool debuggable;
+
+ /** Package data directory like "/data/user/0/com.android.blah" */
+ char* data_dir;
+
+ /** Package SELinux info. */
+ char* seinfo;
+
+ /** Package's list of gids. */
+ gid_list gids;
+
+ /** Spare pointer for the caller to stash extra data off. */
+ void* private_data;
+
+ /** Package's AndroidManifest.xml profileable flag. */
+ bool profileable_from_shell;
+
+ /** Package's AndroidManifest.xml version code. */
+ long version_code;
+} pkg_info;
/**
- * 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.
+ * Parses the system's default package list.
+ * Invokes `callback` once for each package.
+ * The callback owns the `pkg_info*` and should call packagelist_free().
+ * The callback should return `false` to exit early or `true` to continue.
*/
-typedef bool (*pfn_on_package)(pkg_info *info, void *userdata);
+bool packagelist_parse(bool (*callback)(pkg_info* info, void* user_data), void* user_data);
/**
- * 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.
+ * Parses the given package list.
+ * Invokes `callback` once for each package.
+ * The callback owns the `pkg_info*` and should call packagelist_free().
+ * The callback should return `false` to exit early or `true` to continue.
*/
-extern bool packagelist_parse(pfn_on_package callback, void *userdata);
+bool packagelist_parse_file(const char* path, bool (*callback)(pkg_info* info, void* user_data),
+ void* user_data);
-/**
- * Frees a pkg_info structure.
- * @param info
- * The struct to free
- */
-extern void packagelist_free(pkg_info *info);
+/** Frees the given `pkg_info`. */
+void packagelist_free(pkg_info* info);
__END_DECLS
-
-#endif /* PACKAGELISTPARSER_H_ */
diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
deleted file mode 100644
index edc533c..0000000
--- a/libpackagelistparser/packagelistparser.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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>
- *
- */
-
-#define LOG_TAG "packagelistparser"
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/limits.h>
-
-#include <log/log.h>
-#include <packagelistparser/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;
- }
- }
-
- cur = strsep(&next, " \t\r\n");
- if (cur) {
- tmp = strtoul(cur, &endptr, 10);
- if (*endptr != '\0') {
- errmsg = "Could not convert field \"profileable_from_shell\" to integer value";
- goto err;
- }
-
- /* should be a valid boolean of 1 or 0 */
- if (!(tmp == 0 || tmp == 1)) {
- errmsg = "Field \"profileable_from_shell\" is not 0 or 1 boolean value";
- goto err;
- }
-
- pkg_info->profileable_from_shell = (bool)tmp;
- }
- cur = strsep(&next, " \t\r\n");
- if (cur) {
- tmp = strtoul(cur, &endptr, 10);
- if (*endptr != '\0') {
- errmsg = "Could not convert field \"versionCode\" to integer value";
- goto err;
- }
- pkg_info->version_code = tmp;
- }
-
- 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/libpackagelistparser/packagelistparser.cpp b/libpackagelistparser/packagelistparser.cpp
new file mode 100644
index 0000000..59c3a74
--- /dev/null
+++ b/libpackagelistparser/packagelistparser.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 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_TAG "packagelistparser"
+
+#include <packagelistparser/packagelistparser.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/limits.h>
+
+#include <memory>
+
+#include <log/log.h>
+
+static bool parse_gids(const char* path, size_t line_number, const char* gids, pkg_info* info) {
+ // Nothing to do?
+ if (!gids || !strcmp(gids, "none")) return true;
+
+ // How much space do we need?
+ info->gids.cnt = 1;
+ for (const char* p = gids; *p; ++p) {
+ if (*p == ',') ++info->gids.cnt;
+ }
+
+ // Allocate the space.
+ info->gids.gids = new gid_t[info->gids.cnt];
+ if (!info->gids.gids) return false;
+
+ // And parse the individual gids.
+ size_t i = 0;
+ while (true) {
+ char* end;
+ unsigned long gid = strtoul(gids, &end, 10);
+ if (gid > GID_MAX) {
+ ALOGE("%s:%zu: gid %lu > GID_MAX", path, line_number, gid);
+ return false;
+ }
+
+ if (i >= info->gids.cnt) return false;
+ info->gids.gids[i++] = gid;
+
+ if (*end == '\0') return true;
+ if (*end != ',') return false;
+ gids = end + 1;
+ }
+ return true;
+}
+
+static bool parse_line(const char* path, size_t line_number, const char* line, pkg_info* info) {
+ unsigned long uid;
+ int debuggable;
+ char* gid_list;
+ int profileable_from_shell = 0;
+
+ int fields =
+ sscanf(line, "%ms %lu %d %ms %ms %ms %d %ld", &info->name, &uid, &debuggable, &info->data_dir,
+ &info->seinfo, &gid_list, &profileable_from_shell, &info->version_code);
+
+ // Handle the more complicated gids field and free the temporary string.
+ bool gids_okay = parse_gids(path, line_number, gid_list, info);
+ free(gid_list);
+ if (!gids_okay) return false;
+
+ // Did we see enough fields to be getting on with?
+ // The final fields are optional (and not usually present).
+ if (fields < 6) {
+ ALOGE("%s:%zu: too few fields in line", path, line_number);
+ return false;
+ }
+
+ // Extra validation.
+ if (uid > UID_MAX) {
+ ALOGE("%s:%zu: uid %lu > UID_MAX", path, line_number, uid);
+ return false;
+ }
+ info->uid = uid;
+
+ // Integer to bool conversions.
+ info->debuggable = debuggable;
+ info->profileable_from_shell = profileable_from_shell;
+
+ return true;
+}
+
+bool packagelist_parse_file(const char* path, bool (*callback)(pkg_info*, void*), void* user_data) {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path, "re"), &fclose);
+ if (!fp) {
+ ALOGE("couldn't open '%s': %s", path, strerror(errno));
+ return false;
+ }
+
+ size_t line_number = 0;
+ char* line = nullptr;
+ size_t allocated_length = 0;
+ while (getline(&line, &allocated_length, fp.get()) > 0) {
+ ++line_number;
+ std::unique_ptr<pkg_info, decltype(&packagelist_free)> info(
+ static_cast<pkg_info*>(calloc(1, sizeof(pkg_info))), &packagelist_free);
+ if (!info) {
+ ALOGE("%s:%zu: couldn't allocate pkg_info", path, line_number);
+ return false;
+ }
+
+ if (!parse_line(path, line_number, line, info.get())) return false;
+
+ if (!callback(info.release(), user_data)) break;
+ }
+ free(line);
+ return true;
+}
+
+bool packagelist_parse(bool (*callback)(pkg_info*, void*), void* user_data) {
+ return packagelist_parse_file("/data/system/packages.list", callback, user_data);
+}
+
+void packagelist_free(pkg_info* info) {
+ if (!info) return;
+
+ free(info->name);
+ free(info->data_dir);
+ free(info->seinfo);
+ delete[] info->gids.gids;
+ free(info);
+}
diff --git a/libpackagelistparser/packagelistparser_test.cpp b/libpackagelistparser/packagelistparser_test.cpp
new file mode 100644
index 0000000..76cb886
--- /dev/null
+++ b/libpackagelistparser/packagelistparser_test.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <packagelistparser/packagelistparser.h>
+
+#include <memory>
+
+#include <android-base/file.h>
+
+#include <gtest/gtest.h>
+
+TEST(packagelistparser, smoke) {
+ TemporaryFile tf;
+ android::base::WriteStringToFile(
+ // No gids.
+ "com.test.a0 10014 0 /data/user/0/com.test.a0 platform:privapp:targetSdkVersion=19 none\n"
+ // One gid.
+ "com.test.a1 10007 1 /data/user/0/com.test.a1 platform:privapp:targetSdkVersion=21 1023\n"
+ // Multiple gids.
+ "com.test.a2 10011 0 /data/user/0/com.test.a2 media:privapp:targetSdkVersion=30 "
+ "2001,1065,1023,3003,3007,1024\n"
+ // The two new fields (profileable flag and version code).
+ "com.test.a3 10022 0 /data/user/0/com.test.a3 selabel:blah none 1 123\n",
+ tf.path);
+
+ std::vector<pkg_info*> packages;
+ packagelist_parse_file(
+ tf.path,
+ [](pkg_info* info, void* user_data) -> bool {
+ reinterpret_cast<std::vector<pkg_info*>*>(user_data)->push_back(info);
+ return true;
+ },
+ &packages);
+
+ ASSERT_EQ(4U, packages.size());
+
+ ASSERT_STREQ("com.test.a0", packages[0]->name);
+ ASSERT_EQ(10014, packages[0]->uid);
+ ASSERT_FALSE(packages[0]->debuggable);
+ ASSERT_STREQ("/data/user/0/com.test.a0", packages[0]->data_dir);
+ ASSERT_STREQ("platform:privapp:targetSdkVersion=19", packages[0]->seinfo);
+ ASSERT_EQ(0U, packages[0]->gids.cnt);
+ ASSERT_FALSE(packages[0]->profileable_from_shell);
+ ASSERT_EQ(0, packages[0]->version_code);
+
+ ASSERT_STREQ("com.test.a1", packages[1]->name);
+ ASSERT_EQ(10007, packages[1]->uid);
+ ASSERT_TRUE(packages[1]->debuggable);
+ ASSERT_STREQ("/data/user/0/com.test.a1", packages[1]->data_dir);
+ ASSERT_STREQ("platform:privapp:targetSdkVersion=21", packages[1]->seinfo);
+ ASSERT_EQ(1U, packages[1]->gids.cnt);
+ ASSERT_EQ(1023U, packages[1]->gids.gids[0]);
+ ASSERT_FALSE(packages[0]->profileable_from_shell);
+ ASSERT_EQ(0, packages[0]->version_code);
+
+ ASSERT_STREQ("com.test.a2", packages[2]->name);
+ ASSERT_EQ(10011, packages[2]->uid);
+ ASSERT_FALSE(packages[2]->debuggable);
+ ASSERT_STREQ("/data/user/0/com.test.a2", packages[2]->data_dir);
+ ASSERT_STREQ("media:privapp:targetSdkVersion=30", packages[2]->seinfo);
+ ASSERT_EQ(6U, packages[2]->gids.cnt);
+ ASSERT_EQ(2001U, packages[2]->gids.gids[0]);
+ ASSERT_EQ(1024U, packages[2]->gids.gids[5]);
+ ASSERT_FALSE(packages[0]->profileable_from_shell);
+ ASSERT_EQ(0, packages[0]->version_code);
+
+ ASSERT_STREQ("com.test.a3", packages[3]->name);
+ ASSERT_EQ(10022, packages[3]->uid);
+ ASSERT_FALSE(packages[3]->debuggable);
+ ASSERT_STREQ("/data/user/0/com.test.a3", packages[3]->data_dir);
+ ASSERT_STREQ("selabel:blah", packages[3]->seinfo);
+ ASSERT_EQ(0U, packages[3]->gids.cnt);
+ ASSERT_TRUE(packages[3]->profileable_from_shell);
+ ASSERT_EQ(123, packages[3]->version_code);
+
+ for (auto& package : packages) packagelist_free(package);
+}
+
+TEST(packagelistparser, early_exit) {
+ TemporaryFile tf;
+ android::base::WriteStringToFile(
+ "com.test.a0 1 0 / a none\n"
+ "com.test.a1 1 0 / a none\n"
+ "com.test.a2 1 0 / a none\n",
+ tf.path);
+
+ std::vector<pkg_info*> packages;
+ packagelist_parse_file(
+ tf.path,
+ [](pkg_info* info, void* user_data) -> bool {
+ std::vector<pkg_info*>* p = reinterpret_cast<std::vector<pkg_info*>*>(user_data);
+ p->push_back(info);
+ return p->size() < 2;
+ },
+ &packages);
+
+ ASSERT_EQ(2U, packages.size());
+
+ ASSERT_STREQ("com.test.a0", packages[0]->name);
+ ASSERT_STREQ("com.test.a1", packages[1]->name);
+
+ for (auto& package : packages) packagelist_free(package);
+}
+
+TEST(packagelistparser, system_package_list) {
+ // Check that we can actually read the packages.list installed on the device.
+ std::vector<pkg_info*> packages;
+ packagelist_parse(
+ [](pkg_info* info, void* user_data) -> bool {
+ reinterpret_cast<std::vector<pkg_info*>*>(user_data)->push_back(info);
+ return true;
+ },
+ &packages);
+ // Not much we can say for sure about what we expect, other than that there
+ // are likely to be lots of packages...
+ ASSERT_GT(packages.size(), 10U);
+}
+
+TEST(packagelistparser, packagelist_free_nullptr) {
+ packagelist_free(nullptr);
+}