Merge commit '536dea9d61a032e64bbe584a97463c6638ead009' into HEAD

Change-Id: I5c469a4b738629d99d721cad7ded02d6c35f56d5
This commit is contained in:
The Android Open Source Project 2013-11-22 11:28:10 -08:00 committed by Conley Owens
commit 66ed50af68
215 changed files with 24509 additions and 4723 deletions

View file

@ -50,3 +50,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)

0
MODULE_LICENSE_APACHE2 Normal file
View file

324
NOTICE Normal file
View file

@ -0,0 +1,324 @@
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for the Android-specific code. ==
=========================================================================
Android Code
Copyright 2005-2008 The Android Open Source Project
This product includes software developed as part of
The Android Open Source Project (http://source.android.com).
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for Apache Commons code. ==
=========================================================================
Apache Commons
Copyright 1999-2006 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for Jakarta Commons Logging. ==
=========================================================================
Jakarta Commons Logging (JCL)
Copyright 2005,2006 The Apache Software Foundation.
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for the Nuance code. ==
=========================================================================
These files are Copyright 2007 Nuance Communications, but released under
the Apache2 License.
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for the Media Codecs code. ==
=========================================================================
Media Codecs
These files are Copyright 1998 - 2009 PacketVideo, but released under
the Apache2 License.
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for the TagSoup code. ==
=========================================================================
This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
TagSoup is licensed under the Apache License,
Version 2.0. You may obtain a copy of this license at
http://www.apache.org/licenses/LICENSE-2.0 . You may also have
additional legal rights not granted by this license.
TagSoup is distributed in the hope that it will be useful, but
unless required by applicable law or agreed to in writing, TagSoup
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied; not even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for Additional Codecs code. ==
=========================================================================
Additional Codecs
These files are Copyright 2003-2010 VisualOn, but released under
the Apache2 License.
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
== in this case for the Audio Effects code. ==
=========================================================================
Audio Effects
These files are Copyright (C) 2004-2010 NXP Software and
Copyright (C) 2010 The Android Open Source Project, but released under
the Apache2 License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
Unicode Data Files include all data files under the directories
http://www.unicode.org/Public/, http://www.unicode.org/reports/,
and http://www.unicode.org/cldr/data/ . Unicode Software includes any
source code published in the Unicode Standard or under the directories
http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
http://www.unicode.org/cldr/data/.
NOTICE TO USER: Carefully read the following legal agreement. BY
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA
FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY
ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF
THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY,
DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
COPYRIGHT AND PERMISSION NOTICE
Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed
under the Terms of Use in http://www.unicode.org/copyright.html.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Unicode data files and any associated documentation (the
"Data Files") or Unicode software and any associated documentation (the
"Software") to deal in the Data Files or Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, and/or sell copies of the Data Files or Software,
and to permit persons to whom the Data Files or Software are furnished to
do so, provided that (a) the above copyright notice(s) and this permission
notice appear with all copies of the Data Files or Software, (b) both the
above copyright notice(s) and this permission notice appear in associated
documentation, and (c) there is clear notice in each modified Data File
or in the Software as well as in the documentation associated with the
Data File(s) or Software that the data or software has been modified.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in these Data Files or Software without prior written
authorization of the copyright holder.

View file

@ -64,7 +64,6 @@ LOCAL_SRC_FILES := \
file_sync_client.c \
$(EXTRA_SRCS) \
$(USB_SRCS) \
utils.c \
usb_vendors.c
LOCAL_C_INCLUDES += external/openssl/include
@ -116,8 +115,7 @@ LOCAL_SRC_FILES := \
framebuffer_service.c \
remount_service.c \
usb_linux_client.c \
log_service.c \
utils.c
log_service.c
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
@ -132,7 +130,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt
include $(BUILD_EXECUTABLE)
@ -157,7 +155,6 @@ LOCAL_SRC_FILES := \
file_sync_client.c \
get_my_path_linux.c \
usb_linux.c \
utils.c \
usb_vendors.c \
fdevent.c

View file

@ -225,27 +225,6 @@ framebuffer:
If the adbd daemon doesn't have sufficient privileges to open
the framebuffer device, the connection is simply closed immediately.
dns:<server-name>
This service is an exception because it only runs within the ADB server.
It is used to implement USB networking, i.e. to provide a network connection
to the device through the host machine (note: this is the exact opposite of
network tethering).
It is used to perform a gethostbyname(<address>) on the host and return
the corresponding IP address as a 4-byte string.
recover:<size>
This service is used to upload a recovery image to the device. <size>
must be a number corresponding to the size of the file. The service works
by:
- creating a file named /tmp/update
- reading 'size' bytes from the client and writing them to /tmp/update
- when everything is read successfully, create a file named /tmp/update.start
This service can only work when the device is in recovery mode. Otherwise,
the /tmp directory doesn't exist and the connection will be closed immediately.
jdwp:<pid>
Connects to the JDWP thread running in the VM of process <pid>.

134
adb/adb.c
View file

@ -34,6 +34,7 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#if !ADB_HOST
#include <cutils/properties.h>
#include <private/android_filesystem_config.h>
#include <sys/capability.h>
#include <linux/prctl.h>
@ -1199,7 +1200,7 @@ static void drop_capabilities_bounding_set_if_needed() {
#endif
int i;
for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
if ((i == CAP_SETUID) || (i == CAP_SETGID)) {
if (i == CAP_SETUID || i == CAP_SETGID) {
// CAP_SETUID CAP_SETGID needed by /system/bin/run-as
continue;
}
@ -1301,13 +1302,6 @@ int adb_main(int is_daemon, int server_port)
/* don't listen on a port (default 5037) if running in secure mode */
/* don't run as root if we are running in secure mode */
if (should_drop_privileges()) {
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap[2];
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
exit(1);
}
drop_capabilities_bounding_set_if_needed();
/* add extra groups:
@ -1337,16 +1331,6 @@ int adb_main(int is_daemon, int server_port)
exit(1);
}
memset(&header, 0, sizeof(header));
memset(cap, 0, sizeof(cap));
/* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
header.version = _LINUX_CAPABILITY_VERSION_3;
header.pid = 0;
cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
capset(&header, cap);
D("Local port disabled\n");
} else {
char local_name[30];
@ -1404,105 +1388,6 @@ int adb_main(int is_daemon, int server_port)
return 0;
}
#if ADB_HOST
void connect_device(char* host, char* buffer, int buffer_size)
{
int port, fd;
char* portstr = strchr(host, ':');
char hostbuf[100];
char serial[100];
strncpy(hostbuf, host, sizeof(hostbuf) - 1);
if (portstr) {
if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
snprintf(buffer, buffer_size, "bad host name %s", host);
return;
}
// zero terminate the host at the point we found the colon
hostbuf[portstr - host] = 0;
if (sscanf(portstr + 1, "%d", &port) == 0) {
snprintf(buffer, buffer_size, "bad port number %s", portstr);
return;
}
} else {
port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
}
snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
if (find_transport(serial)) {
snprintf(buffer, buffer_size, "already connected to %s", serial);
return;
}
fd = socket_network_client(hostbuf, port, SOCK_STREAM);
if (fd < 0) {
snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
return;
}
D("client: connected on remote on fd %d\n", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
register_socket_transport(fd, serial, port, 0);
snprintf(buffer, buffer_size, "connected to %s", serial);
}
void connect_emulator(char* port_spec, char* buffer, int buffer_size)
{
char* port_separator = strchr(port_spec, ',');
if (!port_separator) {
snprintf(buffer, buffer_size,
"unable to parse '%s' as <console port>,<adb port>",
port_spec);
return;
}
// Zero-terminate console port and make port_separator point to 2nd port.
*port_separator++ = 0;
int console_port = strtol(port_spec, NULL, 0);
int adb_port = strtol(port_separator, NULL, 0);
if (!(console_port > 0 && adb_port > 0)) {
*(port_separator - 1) = ',';
snprintf(buffer, buffer_size,
"Invalid port numbers: Expected positive numbers, got '%s'",
port_spec);
return;
}
/* Check if the emulator is already known.
* Note: There's a small but harmless race condition here: An emulator not
* present just yet could be registered by another invocation right
* after doing this check here. However, local_connect protects
* against double-registration too. From here, a better error message
* can be produced. In the case of the race condition, the very specific
* error message won't be shown, but the data doesn't get corrupted. */
atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
if (known_emulator != NULL) {
snprintf(buffer, buffer_size,
"Emulator on port %d already registered.", adb_port);
return;
}
/* Check if more emulators can be registered. Similar unproblematic
* race condition as above. */
int candidate_slot = get_available_local_transport_index();
if (candidate_slot < 0) {
snprintf(buffer, buffer_size, "Cannot accept more emulators.");
return;
}
/* Preconditions met, try to connect to the emulator. */
if (!local_connect_arbitrary_ports(console_port, adb_port)) {
snprintf(buffer, buffer_size,
"Connected to emulator on ports %d,%d", console_port, adb_port);
} else {
snprintf(buffer, buffer_size,
"Could not connect to emulator on ports %d,%d",
console_port, adb_port);
}
}
#endif
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
{
atransport *transport = NULL;
@ -1563,21 +1448,6 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
}
}
// add a new TCP transport, device or emulator
if (!strncmp(service, "connect:", 8)) {
char buffer[4096];
char* host = service + 8;
if (!strncmp(host, "emu:", 4)) {
connect_emulator(host + 4, buffer, sizeof(buffer));
} else {
connect_device(host, buffer, sizeof(buffer));
}
// Send response for emulator and device
snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
writex(reply_fd, buf, strlen(buf));
return 0;
}
// remove TCP transport
if (!strncmp(service, "disconnect:", 11)) {
char buffer[4096];

View file

@ -128,10 +128,7 @@ struct asocket {
*/
void (*close)(asocket *s);
/* socket-type-specific extradata */
void *extra;
/* A socket is bound to atransport */
/* A socket is bound to atransport */
atransport *transport;
};
@ -292,7 +289,7 @@ void init_usb_transport(atransport *t, usb_handle *usb, int state);
void close_usb_devices();
/* cause new transports to be init'd and added to the list */
void register_socket_transport(int s, const char *serial, int port, int local);
int register_socket_transport(int s, const char *serial, int port, int local);
/* these should only be used for the "adb disconnect" command */
void unregister_transport(atransport *t);

View file

@ -22,7 +22,7 @@
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <cutils/logger.h>
#include <log/logger.h>
#include "sysdeps.h"
#include "adb.h"

View file

@ -6,7 +6,6 @@
#ifndef ADB_MUTEX
#error ADB_MUTEX not defined when including this file
#endif
ADB_MUTEX(dns_lock)
ADB_MUTEX(socket_list_lock)
ADB_MUTEX(transport_lock)
#if ADB_HOST

View file

@ -72,6 +72,8 @@ static char *find_mount(const char *dir)
static int remount_system()
{
char *dev;
int fd;
int OFF = 0;
if (system_ro == 0) {
return 0;
@ -82,6 +84,13 @@ static int remount_system()
if (!dev)
return -1;
fd = unix_open(dev, O_RDONLY);
if (fd < 0)
return -1;
ioctl(fd, BLKROSET, &OFF);
adb_close(fd);
system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
free(dev);

View file

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@ -34,6 +35,7 @@
# endif
#else
# include <cutils/android_reboot.h>
# include <cutils/properties.h>
#endif
typedef struct stinfo stinfo;
@ -53,59 +55,7 @@ void *service_bootstrap_func(void *x)
return 0;
}
#if ADB_HOST
ADB_MUTEX_DEFINE( dns_lock );
static void dns_service(int fd, void *cookie)
{
char *hostname = cookie;
struct hostent *hp;
unsigned zero = 0;
adb_mutex_lock(&dns_lock);
hp = gethostbyname(hostname);
free(cookie);
if(hp == 0) {
writex(fd, &zero, 4);
} else {
writex(fd, hp->h_addr, 4);
}
adb_mutex_unlock(&dns_lock);
adb_close(fd);
}
#else
extern int recovery_mode;
static void recover_service(int s, void *cookie)
{
unsigned char buf[4096];
unsigned count = (unsigned) cookie;
int fd;
fd = adb_creat("/tmp/update", 0644);
if(fd < 0) {
adb_close(s);
return;
}
while(count > 0) {
unsigned xfer = (count > 4096) ? 4096 : count;
if(readx(s, buf, xfer)) break;
if(writex(fd, buf, xfer)) break;
count -= xfer;
}
if(count == 0) {
writex(s, "OKAY", 4);
} else {
writex(s, "FAIL", 4);
}
adb_close(fd);
adb_close(s);
fd = adb_creat("/tmp/update.begin", 0644);
adb_close(fd);
}
#if !ADB_HOST
void restart_root_service(int fd, void *cookie)
{
@ -165,6 +115,7 @@ void restart_usb_service(int fd, void *cookie)
void reboot_service(int fd, void *arg)
{
char buf[100];
char property_val[PROPERTY_VALUE_MAX];
int pid, ret;
sync();
@ -182,51 +133,25 @@ void reboot_service(int fd, void *arg)
waitpid(pid, &ret, 0);
}
ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
if (ret >= (int) sizeof(property_val)) {
snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
writex(fd, buf, strlen(buf));
goto cleanup;
}
ret = property_set(ANDROID_RB_PROPERTY, property_val);
if (ret < 0) {
snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
writex(fd, buf, strlen(buf));
}
cleanup:
free(arg);
adb_close(fd);
}
#endif
#if 0
static void echo_service(int fd, void *cookie)
{
char buf[4096];
int r;
char *p;
int c;
for(;;) {
r = adb_read(fd, buf, 4096);
if(r == 0) goto done;
if(r < 0) {
if(errno == EINTR) continue;
else goto done;
}
c = r;
p = buf;
while(c > 0) {
r = write(fd, p, c);
if(r > 0) {
c -= r;
p += r;
continue;
}
if((r < 0) && (errno == EINTR)) continue;
goto done;
}
}
done:
close(fd);
}
#endif
static int create_service_thread(void (*func)(int, void *), void *cookie)
{
stinfo *sti;
@ -413,9 +338,7 @@ int service_to_fd(const char *name)
disable_tcp_nagle(ret);
} else {
#if ADB_HOST
adb_mutex_lock(&dns_lock);
ret = socket_network_client(name + 1, port, SOCK_STREAM);
adb_mutex_unlock(&dns_lock);
#else
return -1;
#endif
@ -434,18 +357,11 @@ int service_to_fd(const char *name)
ret = socket_local_client(name + 16,
ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
#endif
#if ADB_HOST
} else if(!strncmp("dns:", name, 4)){
char *n = strdup(name + 4);
if(n == 0) return -1;
ret = create_service_thread(dns_service, n);
#else /* !ADB_HOST */
#if !ADB_HOST
} else if(!strncmp("dev:", name, 4)) {
ret = unix_open(name + 4, O_RDWR);
} else if(!strncmp(name, "framebuffer:", 12)) {
ret = create_service_thread(framebuffer_service, 0);
} else if(recovery_mode && !strncmp(name, "recover:", 8)) {
ret = create_service_thread(recover_service, (void*) atoi(name + 8));
} else if (!strncmp(name, "jdwp:", 5)) {
ret = create_jdwp_connection_fd(atoi(name+5));
} else if (!strncmp(name, "log:", 4)) {
@ -480,10 +396,6 @@ int service_to_fd(const char *name)
ret = create_service_thread(restart_tcp_service, (void *)port);
} else if(!strncmp(name, "usb:", 4)) {
ret = create_service_thread(restart_usb_service, NULL);
#endif
#if 0
} else if(!strncmp(name, "echo:", 5)){
ret = create_service_thread(echo_service, 0);
#endif
}
if (ret >= 0) {
@ -519,6 +431,124 @@ static void wait_for_state(int fd, void* cookie)
adb_close(fd);
D("wait_for_state is done\n");
}
static void connect_device(char* host, char* buffer, int buffer_size)
{
int port, fd;
char* portstr = strchr(host, ':');
char hostbuf[100];
char serial[100];
int ret;
strncpy(hostbuf, host, sizeof(hostbuf) - 1);
if (portstr) {
if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
snprintf(buffer, buffer_size, "bad host name %s", host);
return;
}
// zero terminate the host at the point we found the colon
hostbuf[portstr - host] = 0;
if (sscanf(portstr + 1, "%d", &port) == 0) {
snprintf(buffer, buffer_size, "bad port number %s", portstr);
return;
}
} else {
port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
}
snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
fd = socket_network_client(hostbuf, port, SOCK_STREAM);
if (fd < 0) {
snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
return;
}
D("client: connected on remote on fd %d\n", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
ret = register_socket_transport(fd, serial, port, 0);
if (ret < 0) {
adb_close(fd);
snprintf(buffer, buffer_size, "already connected to %s", serial);
} else {
snprintf(buffer, buffer_size, "connected to %s", serial);
}
}
void connect_emulator(char* port_spec, char* buffer, int buffer_size)
{
char* port_separator = strchr(port_spec, ',');
if (!port_separator) {
snprintf(buffer, buffer_size,
"unable to parse '%s' as <console port>,<adb port>",
port_spec);
return;
}
// Zero-terminate console port and make port_separator point to 2nd port.
*port_separator++ = 0;
int console_port = strtol(port_spec, NULL, 0);
int adb_port = strtol(port_separator, NULL, 0);
if (!(console_port > 0 && adb_port > 0)) {
*(port_separator - 1) = ',';
snprintf(buffer, buffer_size,
"Invalid port numbers: Expected positive numbers, got '%s'",
port_spec);
return;
}
/* Check if the emulator is already known.
* Note: There's a small but harmless race condition here: An emulator not
* present just yet could be registered by another invocation right
* after doing this check here. However, local_connect protects
* against double-registration too. From here, a better error message
* can be produced. In the case of the race condition, the very specific
* error message won't be shown, but the data doesn't get corrupted. */
atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
if (known_emulator != NULL) {
snprintf(buffer, buffer_size,
"Emulator on port %d already registered.", adb_port);
return;
}
/* Check if more emulators can be registered. Similar unproblematic
* race condition as above. */
int candidate_slot = get_available_local_transport_index();
if (candidate_slot < 0) {
snprintf(buffer, buffer_size, "Cannot accept more emulators.");
return;
}
/* Preconditions met, try to connect to the emulator. */
if (!local_connect_arbitrary_ports(console_port, adb_port)) {
snprintf(buffer, buffer_size,
"Connected to emulator on ports %d,%d", console_port, adb_port);
} else {
snprintf(buffer, buffer_size,
"Could not connect to emulator on ports %d,%d",
console_port, adb_port);
}
}
static void connect_service(int fd, void* cookie)
{
char buf[4096];
char resp[4096];
char *host = cookie;
if (!strncmp(host, "emu:", 4)) {
connect_emulator(host + 4, buf, sizeof(buf));
} else {
connect_device(host, buf, sizeof(buf));
}
// Send response for emulator and device
snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
writex(fd, resp, strlen(resp));
adb_close(fd);
}
#endif
#if ADB_HOST
@ -552,6 +582,10 @@ asocket* host_service_to_socket(const char* name, const char *serial)
int fd = create_service_thread(wait_for_state, sinfo);
return create_local_socket(fd);
} else if (!strncmp(name, "connect:", 8)) {
const char *host = name + 8;
int fd = create_service_thread(connect_service, (void *)host);
return create_local_socket(fd);
}
return NULL;
}

View file

@ -844,7 +844,7 @@ static void smart_socket_close(asocket *s)
free(s);
}
asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
static asocket *create_smart_socket(void)
{
D("Creating smart socket \n");
asocket *s = calloc(1, sizeof(asocket));
@ -852,21 +852,15 @@ asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
s->enqueue = smart_socket_enqueue;
s->ready = smart_socket_ready;
s->close = smart_socket_close;
s->extra = action_cb;
D("SS(%d): created %p\n", s->id, action_cb);
D("SS(%d)\n", s->id);
return s;
}
void smart_socket_action(asocket *s, const char *act)
{
}
void connect_to_smartsocket(asocket *s)
{
D("Connecting to smart socket \n");
asocket *ss = create_smart_socket(smart_socket_action);
asocket *ss = create_smart_socket();
s->peer = ss;
ss->peer = s;
s->ready(s);

View file

@ -261,7 +261,6 @@ extern char* adb_strtok_r(char *str, const char *delim, char **saveptr);
#include "fdevent.h"
#include <cutils/sockets.h>
#include <cutils/properties.h>
#include <cutils/misc.h>
#include <signal.h>
#include <sys/wait.h>

View file

@ -32,6 +32,11 @@ static atransport transport_list = {
.prev = &transport_list,
};
static atransport pending_list = {
.next = &pending_list,
.prev = &pending_list,
};
ADB_MUTEX_DEFINE( transport_lock );
#if ADB_TRACE
@ -645,8 +650,11 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
}
}
/* put us on the master device list */
adb_mutex_lock(&transport_lock);
/* remove from pending list */
t->next->prev = t->prev;
t->prev->next = t->next;
/* put us on the master device list */
t->next = &transport_list;
t->prev = transport_list.prev;
t->next->prev = t;
@ -989,9 +997,10 @@ void close_usb_devices()
}
#endif // ADB_HOST
void register_socket_transport(int s, const char *serial, int port, int local)
int register_socket_transport(int s, const char *serial, int port, int local)
{
atransport *t = calloc(1, sizeof(atransport));
atransport *n;
char buff[32];
if (!serial) {
@ -999,15 +1008,37 @@ void register_socket_transport(int s, const char *serial, int port, int local)
serial = buff;
}
D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
if ( init_socket_transport(t, s, port, local) < 0 ) {
adb_close(s);
if (init_socket_transport(t, s, port, local) < 0) {
free(t);
return;
return -1;
}
if(serial) {
t->serial = strdup(serial);
adb_mutex_lock(&transport_lock);
for (n = pending_list.next; n != &pending_list; n = n->next) {
if (n->serial && !strcmp(serial, n->serial)) {
adb_mutex_unlock(&transport_lock);
free(t);
return -1;
}
}
for (n = transport_list.next; n != &transport_list; n = n->next) {
if (n->serial && !strcmp(serial, n->serial)) {
adb_mutex_unlock(&transport_lock);
free(t);
return -1;
}
}
t->next = &pending_list;
t->prev = pending_list.prev;
t->next->prev = t;
t->prev->next = t;
t->serial = strdup(serial);
adb_mutex_unlock(&transport_lock);
register_transport(t);
return 0;
}
#if ADB_HOST
@ -1077,6 +1108,14 @@ void register_usb_transport(usb_handle *usb, const char *serial, const char *dev
if(devpath) {
t->devpath = strdup(devpath);
}
adb_mutex_lock(&transport_lock);
t->next = &pending_list;
t->prev = pending_list.prev;
t->next->prev = t;
t->prev->next = t;
adb_mutex_unlock(&transport_lock);
register_transport(t);
}

View file

@ -21,6 +21,9 @@
#include "sysdeps.h"
#include <sys/types.h>
#if !ADB_HOST
#include <cutils/properties.h>
#endif
#define TRACE_TAG TRACE_TRANSPORT
#include "adb.h"

View file

@ -1,106 +0,0 @@
/*
* Copyright (C) 2008 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 "utils.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
char*
buff_addc (char* buff, char* buffEnd, int c)
{
int avail = buffEnd - buff;
if (avail <= 0) /* already in overflow mode */
return buff;
if (avail == 1) { /* overflowing, the last byte is reserved for zero */
buff[0] = 0;
return buff + 1;
}
buff[0] = (char) c; /* add char and terminating zero */
buff[1] = 0;
return buff + 1;
}
char*
buff_adds (char* buff, char* buffEnd, const char* s)
{
int slen = strlen(s);
return buff_addb(buff, buffEnd, s, slen);
}
char*
buff_addb (char* buff, char* buffEnd, const void* data, int len)
{
int avail = (buffEnd - buff);
if (avail <= 0 || len <= 0) /* already overflowing */
return buff;
if (len > avail)
len = avail;
memcpy(buff, data, len);
buff += len;
/* ensure there is a terminating zero */
if (buff >= buffEnd) { /* overflow */
buff[-1] = 0;
} else
buff[0] = 0;
return buff;
}
char*
buff_add (char* buff, char* buffEnd, const char* format, ... )
{
int avail;
avail = (buffEnd - buff);
if (avail > 0) {
va_list args;
int nn;
va_start(args, format);
nn = vsnprintf( buff, avail, format, args);
va_end(args);
if (nn < 0) {
/* some C libraries return -1 in case of overflow,
* but they will also do that if the format spec is
* invalid. We assume ADB is not buggy enough to
* trigger that last case. */
nn = avail;
}
else if (nn > avail) {
nn = avail;
}
buff += nn;
/* ensure that there is a terminating zero */
if (buff >= buffEnd)
buff[-1] = 0;
else
buff[0] = 0;
}
return buff;
}

View file

@ -1,68 +0,0 @@
/*
* Copyright (C) 2008 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 _ADB_UTILS_H
#define _ADB_UTILS_H
/* bounded buffer functions */
/* all these functions are used to append data to a bounded buffer.
*
* after each operation, the buffer is guaranteed to be zero-terminated,
* even in the case of an overflow. they all return the new buffer position
* which allows one to use them in succession, only checking for overflows
* at the end. For example:
*
* BUFF_DECL(temp,p,end,1024);
* char* p;
*
* p = buff_addc(temp, end, '"');
* p = buff_adds(temp, end, string);
* p = buff_addc(temp, end, '"');
*
* if (p >= end) {
* overflow detected. note that 'temp' is
* zero-terminated for safety.
* }
* return strdup(temp);
*/
/* tries to add a character to the buffer, in case of overflow
* this will only write a terminating zero and return buffEnd.
*/
char* buff_addc (char* buff, char* buffEnd, int c);
/* tries to add a string to the buffer */
char* buff_adds (char* buff, char* buffEnd, const char* s);
/* tries to add a bytes to the buffer. the input can contain zero bytes,
* but a terminating zero will always be appended at the end anyway
*/
char* buff_addb (char* buff, char* buffEnd, const void* data, int len);
/* tries to add a formatted string to a bounded buffer */
char* buff_add (char* buff, char* buffEnd, const char* format, ... );
/* convenience macro used to define a bounded buffer, as well as
* a 'cursor' and 'end' variables all in one go.
*
* note: this doesn't place an initial terminating zero in the buffer,
* you need to use one of the buff_ functions for this. or simply
* do _cursor[0] = 0 manually.
*/
#define BUFF_DECL(_buff,_cursor,_end,_size) \
char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
#endif /* _ADB_UTILS_H */

View file

@ -31,9 +31,10 @@
#include <sys/stat.h>
#include <sys/poll.h>
#include <log/logd.h>
#include <log/logger.h>
#include <cutils/sockets.h>
#include <cutils/logd.h>
#include <cutils/logger.h>
#include <cutils/properties.h>
#include <cutils/debugger.h>
@ -435,11 +436,13 @@ static int do_server() {
signal(SIGBUS, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
#ifdef SIGSTKFLT
signal(SIGSTKFLT, SIG_DFL);
#endif
// Ignore failed writes to closed sockets
signal(SIGPIPE, SIG_IGN);
logsocket = socket_local_client("logd",
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
if(logsocket < 0) {

View file

@ -29,7 +29,7 @@
#include <private/android_filesystem_config.h>
#include <cutils/logger.h>
#include <log/logger.h>
#include <cutils/properties.h>
#include <backtrace/backtrace.h>

View file

@ -22,7 +22,7 @@
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <cutils/logd.h>
#include <log/logd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <arpa/inet.h>

View file

@ -264,21 +264,7 @@ void generate_ext4_image(struct image_data *image)
int fd;
struct stat st;
#ifdef USE_MINGW
/* Ideally we should use tmpfile() here, the same as with unix version.
* But unfortunately it is not portable as it is not clear whether this
* function opens file in TEXT or BINARY mode.
*
* There are also some reports it is buggy:
* http://pdplab.it.uom.gr/teaching/gcc_manuals/gnulib.html#tmpfile
* http://www.mega-nerd.com/erikd/Blog/Windiots/tmpfile.html
*/
char *filename = tempnam(getenv("TEMP"), "fastboot-format.img");
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
unlink(filename);
#else
fd = fileno(tmpfile());
#endif
make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
fstat(fd, &st);

View file

@ -42,6 +42,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <bootimg.h>
#include <sparse/sparse.h>
@ -53,6 +54,8 @@
#define O_BINARY 0
#endif
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
char cur_product[FB_RESPONSE_SZ + 1];
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
@ -80,6 +83,27 @@ unsigned ramdisk_offset = 0x01000000;
unsigned second_offset = 0x00f00000;
unsigned tags_offset = 0x00000100;
enum fb_buffer_type {
FB_BUFFER,
FB_BUFFER_SPARSE,
};
struct fastboot_buffer {
enum fb_buffer_type type;
void *data;
unsigned int sz;
};
static struct {
char img_name[13];
char sig_name[13];
char part_name[9];
bool is_optional;
} images[3] = {
{"boot.img", "boot.sig", "boot", false},
{"recovery.img", "recovery.sig", "recovery", true},
{"system.img", "system.sig", "system", false},
};
void get_my_path(char *path);
@ -123,44 +147,28 @@ char *find_item(const char *item, const char *product)
return strdup(path);
}
#ifdef _WIN32
void *load_file(const char *fn, unsigned *_sz);
int64_t file_size(const char *fn);
#else
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define off64_t off_t
#endif
int64_t file_size(const char *fn)
static int64_t file_size(int fd)
{
off64_t off;
int fd;
struct stat st;
int ret;
fd = open(fn, O_RDONLY);
if (fd < 0) return -1;
ret = fstat(fd, &st);
off = lseek64(fd, 0, SEEK_END);
close(fd);
return off;
return ret ? -1 : st.st_size;
}
void *load_file(const char *fn, unsigned *_sz)
static void *load_fd(int fd, unsigned *_sz)
{
char *data;
int sz;
int fd;
int errno_tmp;
data = 0;
fd = open(fn, O_RDONLY);
if(fd < 0) return 0;
sz = lseek(fd, 0, SEEK_END);
if(sz < 0) goto oops;
if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
sz = file_size(fd);
if (sz < 0) {
goto oops;
}
data = (char*) malloc(sz);
if(data == 0) goto oops;
@ -178,7 +186,16 @@ oops:
errno = errno_tmp;
return 0;
}
#endif
static void *load_file(const char *fn, unsigned *_sz)
{
int fd;
fd = open(fn, O_RDONLY | O_BINARY);
if(fd < 0) return 0;
return load_fd(fd, _sz);
}
int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
{
@ -385,6 +402,31 @@ void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
return data;
}
static int unzip_to_file(zipfile_t zip, char *name)
{
int fd;
char *data;
unsigned sz;
fd = fileno(tmpfile());
if (fd < 0) {
return -1;
}
data = unzip_file(zip, name, &sz);
if (data == 0) {
return -1;
}
if (write(fd, data, sz) != sz) {
fd = -1;
}
free(data);
lseek(fd, 0, SEEK_SET);
return fd;
}
static char *strip(char *s)
{
int n;
@ -489,27 +531,20 @@ void queue_info_dump(void)
fb_queue_notice("--------------------------------------------");
}
struct sparse_file **load_sparse_files(const char *fname, int max_size)
static struct sparse_file **load_sparse_files(int fd, int max_size)
{
int fd;
struct sparse_file *s;
int files;
struct sparse_file **out_s;
fd = open(fname, O_RDONLY | O_BINARY);
if (fd < 0) {
die("cannot open '%s'\n", fname);
}
s = sparse_file_import_auto(fd, false);
if (!s) {
die("cannot sparse read file '%s'\n", fname);
die("cannot sparse read file\n");
}
files = sparse_file_resparse(s, max_size, NULL, 0);
if (files < 0) {
die("Failed to resparse '%s'\n", fname);
die("Failed to resparse\n");
}
out_s = calloc(sizeof(struct sparse_file *), files + 1);
@ -519,7 +554,7 @@ struct sparse_file **load_sparse_files(const char *fname, int max_size)
files = sparse_file_resparse(s, max_size, out_s, files);
if (files < 0) {
die("Failed to resparse '%s'\n", fname);
die("Failed to resparse\n");
}
return out_s;
@ -580,29 +615,78 @@ static int needs_erase(const char *part)
return fb_format_supported(usb, part);
}
void do_flash(usb_handle *usb, const char *pname, const char *fname)
static int load_buf_fd(usb_handle *usb, int fd,
struct fastboot_buffer *buf)
{
int64_t sz64;
void *data;
int64_t limit;
sz64 = file_size(fname);
sz64 = file_size(fd);
if (sz64 < 0) {
return -1;
}
limit = get_sparse_limit(usb, sz64);
if (limit) {
struct sparse_file **s = load_sparse_files(fname, limit);
struct sparse_file **s = load_sparse_files(fd, limit);
if (s == NULL) {
die("cannot sparse load '%s'\n", fname);
}
while (*s) {
sz64 = sparse_file_len(*s, true, false);
fb_queue_flash_sparse(pname, *s++, sz64);
return -1;
}
buf->type = FB_BUFFER_SPARSE;
buf->data = s;
} else {
unsigned int sz;
data = load_file(fname, &sz);
if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno));
fb_queue_flash(pname, data, sz);
data = load_fd(fd, &sz);
if (data == 0) return -1;
buf->type = FB_BUFFER;
buf->data = data;
buf->sz = sz;
}
return 0;
}
static int load_buf(usb_handle *usb, const char *fname,
struct fastboot_buffer *buf)
{
int fd;
fd = open(fname, O_RDONLY | O_BINARY);
if (fd < 0) {
die("cannot open '%s'\n", fname);
}
return load_buf_fd(usb, fd, buf);
}
static void flash_buf(const char *pname, struct fastboot_buffer *buf)
{
struct sparse_file **s;
switch (buf->type) {
case FB_BUFFER_SPARSE:
s = buf->data;
while (*s) {
int64_t sz64 = sparse_file_len(*s, true, false);
fb_queue_flash_sparse(pname, *s++, sz64);
}
break;
case FB_BUFFER:
fb_queue_flash(pname, buf->data, buf->sz);
break;
default:
die("unknown buffer type: %d", buf->type);
}
}
void do_flash(usb_handle *usb, const char *pname, const char *fname)
{
struct fastboot_buffer buf;
if (load_buf(usb, fname, &buf)) {
die("cannot load '%s'", fname);
}
flash_buf(pname, &buf);
}
void do_update_signature(zipfile_t zip, char *fn)
@ -615,13 +699,17 @@ void do_update_signature(zipfile_t zip, char *fn)
fb_queue_command("signature", "installing signature");
}
void do_update(char *fn, int erase_first)
void do_update(usb_handle *usb, char *fn, int erase_first)
{
void *zdata;
unsigned zsize;
void *data;
unsigned sz;
zipfile_t zip;
int fd;
int rc;
struct fastboot_buffer buf;
int i;
queue_info_dump();
@ -650,30 +738,25 @@ void do_update(char *fn, int erase_first)
setup_requirements(data, sz);
data = unzip_file(zip, "boot.img", &sz);
if (data == 0) die("update package missing boot.img");
do_update_signature(zip, "boot.sig");
if (erase_first && needs_erase("boot")) {
fb_queue_erase("boot");
}
fb_queue_flash("boot", data, sz);
data = unzip_file(zip, "recovery.img", &sz);
if (data != 0) {
do_update_signature(zip, "recovery.sig");
if (erase_first && needs_erase("recovery")) {
fb_queue_erase("recovery");
for (i = 0; i < ARRAY_SIZE(images); i++) {
fd = unzip_to_file(zip, images[i].img_name);
if (fd < 0) {
if (images[i].is_optional)
continue;
die("update package missing %s", images[i].img_name);
}
fb_queue_flash("recovery", data, sz);
rc = load_buf_fd(usb, fd, &buf);
if (rc) die("cannot load %s from flash", images[i].img_name);
do_update_signature(zip, images[i].sig_name);
if (erase_first && needs_erase(images[i].part_name)) {
fb_queue_erase(images[i].part_name);
}
flash_buf(images[i].part_name, &buf);
/* not closing the fd here since the sparse code keeps the fd around
* but hasn't mmaped data yet. The tmpfile will get cleaned up when the
* program exits.
*/
}
data = unzip_file(zip, "system.img", &sz);
if (data == 0) die("update package missing system.img");
do_update_signature(zip, "system.sig");
if (erase_first && needs_erase("system")) {
fb_queue_erase("system");
}
fb_queue_flash("system", data, sz);
}
void do_send_signature(char *fn)
@ -694,11 +777,13 @@ void do_send_signature(char *fn)
fb_queue_command("signature", "installing signature");
}
void do_flashall(int erase_first)
void do_flashall(usb_handle *usb, int erase_first)
{
char *fname;
void *data;
unsigned sz;
struct fastboot_buffer buf;
int i;
queue_info_dump();
@ -710,33 +795,19 @@ void do_flashall(int erase_first)
if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
setup_requirements(data, sz);
fname = find_item("boot", product);
data = load_file(fname, &sz);
if (data == 0) die("could not load boot.img: %s", strerror(errno));
do_send_signature(fname);
if (erase_first && needs_erase("boot")) {
fb_queue_erase("boot");
}
fb_queue_flash("boot", data, sz);
fname = find_item("recovery", product);
data = load_file(fname, &sz);
if (data != 0) {
do_send_signature(fname);
if (erase_first && needs_erase("recovery")) {
fb_queue_erase("recovery");
for (i = 0; i < ARRAY_SIZE(images); i++) {
fname = find_item(images[i].part_name, product);
if (load_buf(usb, fname, &buf)) {
if (images[i].is_optional)
continue;
die("could not load %s\n", images[i].img_name);
}
fb_queue_flash("recovery", data, sz);
do_send_signature(fname);
if (erase_first && needs_erase(images[i].part_name)) {
fb_queue_erase(images[i].part_name);
}
flash_buf(images[i].part_name, &buf);
}
fname = find_item("system", product);
data = load_file(fname, &sz);
if (data == 0) die("could not load system.img: %s", strerror(errno));
do_send_signature(fname);
if (erase_first && needs_erase("system")) {
fb_queue_erase("system");
}
fb_queue_flash("system", data, sz);
}
#define skip(n) do { argc -= (n); argv += (n); } while (0)
@ -996,14 +1067,14 @@ int main(int argc, char **argv)
fb_queue_flash(pname, data, sz);
} else if(!strcmp(*argv, "flashall")) {
skip(1);
do_flashall(erase_first);
do_flashall(usb, erase_first);
wants_reboot = 1;
} else if(!strcmp(*argv, "update")) {
if (argc > 1) {
do_update(argv[1], erase_first);
do_update(usb, argv[1], erase_first);
skip(2);
} else {
do_update("update.zip", erase_first);
do_update(usb, "update.zip", erase_first);
skip(1);
}
wants_reboot = 1;

View file

@ -36,29 +36,6 @@
#include <windows.h>
int64_t file_size(const char *fn)
{
HANDLE file;
char *data;
DWORD sz;
file = CreateFile( fn,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL );
if (file == INVALID_HANDLE_VALUE)
return -1;
sz = GetFileSize( file, NULL );
CloseHandle( file );
return sz;
}
void get_my_path(char exe[PATH_MAX])
{
char* r;
@ -70,47 +47,3 @@ void get_my_path(char exe[PATH_MAX])
*r = 0;
}
void *load_file(const char *fn, unsigned *_sz)
{
HANDLE file;
char *data;
DWORD sz;
file = CreateFile( fn,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL );
if (file == INVALID_HANDLE_VALUE)
return NULL;
sz = GetFileSize( file, NULL );
data = NULL;
if (sz > 0) {
data = (char*) malloc( sz );
if (data == NULL) {
fprintf(stderr, "load_file: could not allocate %ld bytes\n", sz );
sz = 0;
} else {
DWORD out_bytes;
if ( !ReadFile( file, data, sz, &out_bytes, NULL ) ||
out_bytes != sz )
{
fprintf(stderr, "load_file: could not read %ld bytes from '%s'\n", sz, fn);
free(data);
data = NULL;
sz = 0;
}
}
}
CloseHandle( file );
*_sz = (unsigned) sz;
return data;
}

38
fastbootd/Android.mk Normal file
View file

@ -0,0 +1,38 @@
# Copyright (C) 2013 Google Inc.
#
# 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.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
config.c \
commands.c \
fastbootd.c \
protocol.c \
transport.c \
usb_linux_client.c
LOCAL_MODULE := fastbootd
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
LOCAL_STATIC_LIBRARIES := \
libsparse_static \
libc \
libcutils
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)

97
fastbootd/bootimg.h Normal file
View file

@ -0,0 +1,97 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _BOOT_IMAGE_H_
#define _BOOT_IMAGE_H_
typedef struct boot_img_hdr boot_img_hdr;
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned unused[2]; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
/*
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
** 2. second is optional (second_size == 0 -> no second)
** 3. load each element (kernel, ramdisk, second) at
** the specified physical address (kernel_addr, etc)
** 4. prepare tags at tag_addr. kernel_args[] is
** appended to the kernel commandline in the tags.
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
** 6. if second_size != 0: jump to second_addr
** else: jump to kernel_addr
*/
boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
void *ramdisk, unsigned ramdisk_size,
void *second, unsigned second_size,
unsigned page_size,
unsigned *bootimg_size);
void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);
#endif

206
fastbootd/commands.c Normal file
View file

@ -0,0 +1,206 @@
/*
* Copyright (c) 2009-2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include "bootimg.h"
#include "debug.h"
#include "protocol.h"
static void cmd_boot(struct protocol_handle *phandle, const char *arg)
{
#if 0
unsigned kernel_actual;
unsigned ramdisk_actual;
static struct boot_img_hdr hdr;
char *ptr = ((char*) data);
if (sz < sizeof(hdr)) {
fastboot_fail(phandle, "invalid bootimage header");
return;
}
memcpy(&hdr, data, sizeof(hdr));
/* ensure commandline is terminated */
hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
kernel_actual = ROUND_TO_PAGE(hdr.kernel_size);
ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size);
if (2048 + kernel_actual + ramdisk_actual < sz) {
fastboot_fail(phandle, "incomplete bootimage");
return;
}
/*memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size);
memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size);*/
fastboot_okay(phandle, "");
udc_stop();
/*boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR,
(const char*) hdr.cmdline, LINUX_MACHTYPE,
(void*) RAMDISK_ADDR, hdr.ramdisk_size);*/
#endif
}
static void cmd_erase(struct protocol_handle *phandle, const char *arg)
{
#if 0
struct ptentry *ptn;
struct ptable *ptable;
ptable = flash_get_ptable();
if (ptable == NULL) {
fastboot_fail(phandle, "partition table doesn't exist");
return;
}
ptn = ptable_find(ptable, arg);
if (ptn == NULL) {
fastboot_fail(phandle, "unknown partition name");
return;
}
if (flash_erase(ptn)) {
fastboot_fail(phandle, "failed to erase partition");
return;
}
fastboot_okay(phandle, "");
#endif
}
static void cmd_flash(struct protocol_handle *phandle, const char *arg)
{
#if 0
struct ptentry *ptn;
struct ptable *ptable;
unsigned extra = 0;
ptable = flash_get_ptable();
if (ptable == NULL) {
fastboot_fail(phandle, "partition table doesn't exist");
return;
}
ptn = ptable_find(ptable, arg);
if (ptn == NULL) {
fastboot_fail(phandle, "unknown partition name");
return;
}
if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
fastboot_fail(phandle, "image is not a boot image");
return;
}
}
if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata"))
extra = 64;
else
sz = ROUND_TO_PAGE(sz);
D(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
if (flash_write(ptn, extra, data, sz)) {
fastboot_fail(phandle, "flash write failure");
return;
}
D(INFO, "partition '%s' updated\n", ptn->name);
#endif
fastboot_okay(phandle, "");
}
static void cmd_continue(struct protocol_handle *phandle, const char *arg)
{
fastboot_okay(phandle, "");
#if 0
udc_stop();
boot_linux_from_flash();
#endif
}
static void cmd_getvar(struct protocol_handle *phandle, const char *arg)
{
const char *value;
D(DEBUG, "cmd_getvar %s\n", arg);
value = fastboot_getvar(arg);
fastboot_okay(phandle, value);
}
static void cmd_download(struct protocol_handle *phandle, const char *arg)
{
unsigned len = strtoul(arg, NULL, 16);
int old_fd;
if (len > 256 * 1024 * 1024) {
fastboot_fail(phandle, "data too large");
return;
}
fastboot_data(phandle, len);
old_fd = protocol_get_download(phandle);
if (old_fd >= 0) {
off_t len = lseek(old_fd, 0, SEEK_END);
D(INFO, "disposing of unused fd %d, size %ld", old_fd, len);
close(old_fd);
}
phandle->download_fd = protocol_handle_download(phandle, len);
if (phandle->download_fd < 0) {
//handle->state = STATE_ERROR;
fastboot_fail(phandle, "download failed");
return;
}
fastboot_okay(phandle, "");
}
void commands_init()
{
fastboot_register("boot", cmd_boot);
fastboot_register("erase:", cmd_erase);
fastboot_register("flash:", cmd_flash);
fastboot_register("continue", cmd_continue);
fastboot_register("getvar:", cmd_getvar);
fastboot_register("download:", cmd_download);
//fastboot_publish("version", "0.5");
//fastboot_publish("product", "swordfish");
//fastboot_publish("kernel", "lk");
}

161
fastbootd/config.c Normal file
View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "protocol.h"
#include "debug.h"
// TODO: change config path
#define CONFIG_PATH "/data/fastboot.cfg"
static char *strip(char *str)
{
int n;
n = strspn(str, " \t");
str += n;
for (n = strlen(str) - 1; n >= 0; n--) {
if (str[n] == ' ' || str[n] == '\t')
str[n] = '\0';
else
break;
}
return str;
}
static int config_parse_line(char *line)
{
char *c;
char *key;
char *value;
c = strchr(line, '#');
if (c)
*c = '\0';
if (strspn(line, " \t") == strlen(line))
return 0;
c = strchr(line, '=');
if (c == NULL)
return -1;
key = line;
*c = '\0';
value = c + 1;
key = strip(key);
value = strip(value);
key = strdup(key);
value = strdup(value);
fastboot_publish(key, value);
return 0;
}
static void config_parse(char *buffer)
{
char *saveptr;
char *str = buffer;
char *line = buffer;
int c;
int ret;
for (c = 1; line != NULL; c++) {
line = strtok_r(str, "\r\n", &saveptr);
if (line != NULL) {
D(VERBOSE, "'%s'", line);
ret = config_parse_line(line);
if (ret < 0) {
D(WARN, "error parsing " CONFIG_PATH " line %d", c);
}
}
str = NULL;
}
}
void config_init()
{
int fd;
off_t len;
ssize_t ret;
size_t count = 0;
char *buffer;
fd = open(CONFIG_PATH, O_RDONLY);
if (fd < 0) {
D(ERR, "failed to open " CONFIG_PATH);
return;
}
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
D(ERR, "failed to seek to end of " CONFIG_PATH);
return;
}
lseek(fd, 0, SEEK_SET);
buffer = malloc(len + 1);
if (buffer == NULL) {
D(ERR, "failed to allocate %ld bytes", len);
return;
}
while (count < (size_t)len) {
ret = read(fd, buffer + count, len - count);
if (ret < 0 && errno != EINTR) {
D(ERR, "failed to read " CONFIG_PATH ": %d %s", errno, strerror(errno));
return;
}
if (ret == 0) {
D(ERR, "early EOF reading " CONFIG_PATH);
return;
}
count += ret;
}
buffer[len] = '\0';
config_parse(buffer);
free(buffer);
}

42
fastbootd/debug.h Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 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 _FASTBOOTD_DEBUG_H_
#define _FASTBOOTD_DEBUG_H_
#include <stdio.h>
#include <cutils/klog.h>
#define ERR 0
#define WARN 1
#define INFO 2
#define VERBOSE 3
#define DEBUG 4
extern unsigned int debug_level;
//#define DLOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#define DLOG(fmt, ...) KLOG_INFO("fastbootd", fmt, ##__VA_ARGS__)
#define D(level, fmt, ...) \
do { \
if (debug_level == level || debug_level > level) { \
DLOG("%s:%d " fmt "\n", __BASE_FILE__, __LINE__, ##__VA_ARGS__); \
} \
} while (0)
#endif

45
fastbootd/fastbootd.c Normal file
View file

@ -0,0 +1,45 @@
/*
* Copyright (C) 2013 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 <stdio.h>
#include <unistd.h>
#include <cutils/klog.h>
#include "debug.h"
unsigned int debug_level = DEBUG;
void commands_init();
void usb_init();
void config_init();
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
klog_init();
klog_set_level(6);
config_init();
commands_init();
usb_init();
while (1) {
sleep(1);
}
return 0;
}

195
fastbootd/protocol.c Normal file
View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2009-2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "protocol.h"
#include "transport.h"
#define STATE_OFFLINE 0
#define STATE_COMMAND 1
#define STATE_COMPLETE 2
#define STATE_ERROR 3
struct fastboot_cmd {
struct fastboot_cmd *next;
const char *prefix;
unsigned prefix_len;
void (*execute)(struct protocol_handle *phandle, const char *arg);
};
struct fastboot_var {
struct fastboot_var *next;
const char *name;
const char *value;
};
static struct fastboot_cmd *cmdlist;
void fastboot_register(const char *prefix,
void (*phandle)(struct protocol_handle *phandle, const char *arg))
{
struct fastboot_cmd *cmd;
cmd = malloc(sizeof(*cmd));
if (cmd) {
cmd->prefix = prefix;
cmd->prefix_len = strlen(prefix);
cmd->execute = phandle;
cmd->next = cmdlist;
cmdlist = cmd;
}
}
static struct fastboot_var *varlist;
void fastboot_publish(const char *name, const char *value)
{
struct fastboot_var *var;
var = malloc(sizeof(*var));
if (var) {
var->name = name;
var->value = value;
var->next = varlist;
varlist = var;
}
}
const char *fastboot_getvar(const char *name)
{
struct fastboot_var *var;
for (var = varlist; var; var = var->next) {
if (!strcmp(var->name, name)) {
return var->value;
}
}
return "";
}
int protocol_handle_download(struct protocol_handle *phandle, size_t len)
{
return transport_handle_download(phandle->transport_handle, len);
}
static ssize_t protocol_handle_write(struct protocol_handle *phandle,
char *buffer, size_t len)
{
return transport_handle_write(phandle->transport_handle, buffer, len);
}
static void fastboot_ack(struct protocol_handle *phandle, const char *code,
const char *reason)
{
char response[64];
if (phandle->state != STATE_COMMAND)
return;
if (reason == 0)
reason = "";
snprintf(response, 64, "%s%s", code, reason);
phandle->state = STATE_COMPLETE;
protocol_handle_write(phandle, response, strlen(response));
}
void fastboot_fail(struct protocol_handle *phandle, const char *reason)
{
fastboot_ack(phandle, "FAIL", reason);
}
void fastboot_okay(struct protocol_handle *phandle, const char *info)
{
fastboot_ack(phandle, "OKAY", info);
}
void fastboot_data(struct protocol_handle *phandle, size_t len)
{
char response[64];
ssize_t ret;
snprintf(response, 64, "DATA%08x", len);
ret = protocol_handle_write(phandle, response, strlen(response));
if (ret < 0)
return;
}
void protocol_handle_command(struct protocol_handle *phandle, char *buffer)
{
D(INFO,"fastboot: %s\n", buffer);
struct fastboot_cmd *cmd;
for (cmd = cmdlist; cmd; cmd = cmd->next) {
if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
continue;
phandle->state = STATE_COMMAND;
cmd->execute(phandle, buffer + cmd->prefix_len);
if (phandle->state == STATE_COMMAND)
fastboot_fail(phandle, "unknown reason");
return;
}
fastboot_fail(phandle, "unknown command");
}
struct protocol_handle *create_protocol_handle(struct transport_handle *thandle)
{
struct protocol_handle *phandle;
phandle = calloc(sizeof(struct protocol_handle), 1);
phandle->transport_handle = thandle;
phandle->state = STATE_OFFLINE;
phandle->download_fd = -1;
pthread_mutex_init(&phandle->lock, NULL);
return phandle;
}
int protocol_get_download(struct protocol_handle *phandle)
{
int fd;
pthread_mutex_lock(&phandle->lock);
fd = phandle->download_fd;
phandle->download_fd = -1;
pthread_mutex_unlock(&phandle->lock);
return fd;
}

61
fastbootd/protocol.h Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _FASTBOOTD_PROTOCOL_H_
#define _FASTBOOTD_PROTOCOL_H_
#include <pthread.h>
#include <stddef.h>
struct protocol_handle {
struct transport_handle *transport_handle;
unsigned int state;
int download_fd;
pthread_mutex_t lock;
};
void fastboot_register(const char *prefix,
void (*handle)(struct protocol_handle *handle, const char *arg));
void fastboot_publish(const char *name, const char *value);
const char *fastboot_getvar(const char *name);
struct protocol_handle *create_protocol_handle(struct transport_handle *t);
void protocol_handle_command(struct protocol_handle *handle, char *buffer);
int protocol_handle_download(struct protocol_handle *phandle, size_t len);
int protocol_get_download(struct protocol_handle *phandle);
void fastboot_fail(struct protocol_handle *handle, const char *reason);
void fastboot_okay(struct protocol_handle *handle, const char *reason);
void fastboot_data(struct protocol_handle *handle, size_t len);
#endif

149
fastbootd/transport.c Normal file
View file

@ -0,0 +1,149 @@
/*
* Copyright (C) 2013 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 <pthread.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include "debug.h"
#include "protocol.h"
#include "transport.h"
#define COMMAND_BUF_SIZE 64
ssize_t transport_handle_write(struct transport_handle *thandle, char *buffer, size_t len)
{
return thandle->transport->write(thandle, buffer, len);
}
void transport_handle_close(struct transport_handle *thandle)
{
thandle->transport->close(thandle);
}
int transport_handle_download(struct transport_handle *thandle, size_t len)
{
ssize_t ret;
size_t n = 0;
int fd;
// TODO: move out of /dev
char tempname[] = "/dev/fastboot_download_XXXXXX";
char *buffer;
fd = mkstemp(tempname);
if (fd < 0)
return -1;
unlink(tempname);
ftruncate(fd, len);
buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buffer == NULL) {
D(ERR, "mmap(%u) failed: %d %s", len, errno, strerror(errno));
goto err;
}
while (n < len) {
ret = thandle->transport->read(thandle, buffer + n, len - n);
if (ret <= 0) {
D(WARN, "transport read failed, ret=%d %s", ret, strerror(-ret));
break;
}
n += ret;
}
munmap(buffer, len);
if (n != len)
goto err;
return fd;
err:
close(fd);
transport_handle_close(thandle);
return -1;
}
static void *transport_data_thread(void *arg)
{
struct transport_handle *thandle = arg;
struct protocol_handle *phandle = create_protocol_handle(thandle);
while (!thandle->stopped) {
int ret;
char buffer[COMMAND_BUF_SIZE + 1];
D(VERBOSE, "transport_data_thread\n");
ret = thandle->transport->read(thandle, buffer, COMMAND_BUF_SIZE);
if (ret <= 0) {
D(DEBUG, "ret = %d\n", ret);
break;
}
if (ret > 0) {
buffer[ret] = 0;
protocol_handle_command(phandle, buffer);
}
}
transport_handle_close(thandle);
free(thandle);
return NULL;
}
static void *transport_connect_thread(void *arg)
{
struct transport *transport = arg;
while (!transport->stopped) {
struct transport_handle *thandle;
pthread_t thread;
pthread_attr_t attr;
D(VERBOSE, "transport_connect_thread\n");
thandle = transport->connect(transport);
if (thandle == NULL) {
D(ERR, "transport connect failed\n");
sleep(1);
continue;
}
thandle->transport = transport;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &attr, transport_data_thread, thandle);
sleep(1);
}
return NULL;
}
void transport_register(struct transport *transport)
{
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &attr, transport_connect_thread, transport);
}

41
fastbootd/transport.h Normal file
View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2013 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 _FASTBOOTD_TRANSPORT_H_
#define _FASTBOOTD_TRANSPORT_H_
#include <stdbool.h>
struct transport_handle {
struct transport *transport;
bool stopped;
};
struct transport {
void (*init)();
void (*close)(struct transport_handle *thandle);
ssize_t (*read)(struct transport_handle *thandle, void *data, size_t len);
ssize_t (*write)(struct transport_handle *thandle, const void *data, size_t len);
struct transport_handle *(*connect)(struct transport *transport);
bool stopped;
};
void transport_register(struct transport *transport);
ssize_t transport_handle_write(struct transport_handle *handle, char *buffer, size_t len);
int transport_handle_download(struct transport_handle *handle, size_t len);
#endif

View file

@ -0,0 +1,353 @@
/*
* Copyright (C) 2007 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 <endian.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/usb/ch9.h>
#include <linux/usb/functionfs.h>
#include "debug.h"
#include "transport.h"
#define TRACE_TAG TRACE_USB
#define MAX_PACKET_SIZE_FS 64
#define MAX_PACKET_SIZE_HS 512
#define cpu_to_le16(x) htole16(x)
#define cpu_to_le32(x) htole32(x)
#define FASTBOOT_CLASS 0xff
#define FASTBOOT_SUBCLASS 0x42
#define FASTBOOT_PROTOCOL 0x3
#define USB_FFS_FASTBOOT_PATH "/dev/usb-ffs/adb/"
#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x
#define USB_FFS_FASTBOOT_EP0 USB_FFS_FASTBOOT_EP(ep0)
#define USB_FFS_FASTBOOT_OUT USB_FFS_FASTBOOT_EP(ep1)
#define USB_FFS_FASTBOOT_IN USB_FFS_FASTBOOT_EP(ep2)
#define READ_BUF_SIZE (16*1024)
#define container_of(ptr, type, member) \
((type*)((char*)(ptr) - offsetof(type, member)))
struct usb_transport {
struct transport transport;
pthread_cond_t notify;
pthread_mutex_t lock;
int control;
int bulk_out; /* "out" from the host's perspective => source for fastbootd */
int bulk_in; /* "in" from the host's perspective => sink for fastbootd */
};
struct usb_handle {
struct transport_handle handle;
};
static const struct {
struct usb_functionfs_descs_head header;
struct {
struct usb_interface_descriptor intf;
struct usb_endpoint_descriptor_no_audio source;
struct usb_endpoint_descriptor_no_audio sink;
} __attribute__((packed)) fs_descs, hs_descs;
} __attribute__((packed)) descriptors = {
.header = {
.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
.length = cpu_to_le32(sizeof(descriptors)),
.fs_count = 3,
.hs_count = 3,
},
.fs_descs = {
.intf = {
.bLength = sizeof(descriptors.fs_descs.intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bNumEndpoints = 2,
.bInterfaceClass = FASTBOOT_CLASS,
.bInterfaceSubClass = FASTBOOT_SUBCLASS,
.bInterfaceProtocol = FASTBOOT_PROTOCOL,
.iInterface = 1, /* first string from the provided table */
},
.source = {
.bLength = sizeof(descriptors.fs_descs.source),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 1 | USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = MAX_PACKET_SIZE_FS,
},
.sink = {
.bLength = sizeof(descriptors.fs_descs.sink),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 2 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = MAX_PACKET_SIZE_FS,
},
},
.hs_descs = {
.intf = {
.bLength = sizeof(descriptors.hs_descs.intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bNumEndpoints = 2,
.bInterfaceClass = FASTBOOT_CLASS,
.bInterfaceSubClass = FASTBOOT_SUBCLASS,
.bInterfaceProtocol = FASTBOOT_PROTOCOL,
.iInterface = 1, /* first string from the provided table */
},
.source = {
.bLength = sizeof(descriptors.hs_descs.source),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 1 | USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = MAX_PACKET_SIZE_HS,
},
.sink = {
.bLength = sizeof(descriptors.hs_descs.sink),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 2 | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = MAX_PACKET_SIZE_HS,
},
},
};
#define STR_INTERFACE_ "Fastboot Interface"
static const struct {
struct usb_functionfs_strings_head header;
struct {
__le16 code;
const char str1[sizeof(STR_INTERFACE_)];
} __attribute__((packed)) lang0;
} __attribute__((packed)) strings = {
.header = {
.magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
.length = cpu_to_le32(sizeof(strings)),
.str_count = cpu_to_le32(1),
.lang_count = cpu_to_le32(1),
},
.lang0 = {
cpu_to_le16(0x0409), /* en-us */
STR_INTERFACE_,
},
};
static int init_functionfs(struct usb_transport *usb_transport)
{
ssize_t ret;
D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
if (usb_transport->control < 0) {
D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
goto err;
}
ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
if (ret < 0) {
D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
goto err;
}
ret = write(usb_transport->control, &strings, sizeof(strings));
if (ret < 0) {
D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
goto err;
}
usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR);
if (usb_transport->bulk_out < 0) {
D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno);
goto err;
}
usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR);
if (usb_transport->bulk_in < 0) {
D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno);
goto err;
}
return 0;
err:
if (usb_transport->bulk_in > 0) {
close(usb_transport->bulk_in);
usb_transport->bulk_in = -1;
}
if (usb_transport->bulk_out > 0) {
close(usb_transport->bulk_out);
usb_transport->bulk_out = -1;
}
if (usb_transport->control > 0) {
close(usb_transport->control);
usb_transport->control = -1;
}
return -1;
}
static ssize_t bulk_write(int bulk_in, const char *buf, size_t length)
{
size_t count = 0;
ssize_t ret;
do {
ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
if (ret < 0) {
D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
bulk_in, length, errno, strerror(errno));
return -1;
} else {
count += ret;
}
} while (count < length);
D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in);
return count;
}
static ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
{
ssize_t ret;
struct transport *t = thandle->transport;
struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
D(DEBUG, "about to write (fd=%d, len=%d)", usb_transport->bulk_in, len);
ret = bulk_write(usb_transport->bulk_in, data, len);
if (ret < 0) {
D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
return -1;
}
D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in);
return ret;
}
static ssize_t bulk_read(int bulk_out, char *buf, size_t length)
{
ssize_t ret;
size_t n = 0;
while (n < length) {
size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
if (ret < 0) {
D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
bulk_out, length, errno, strerror(errno));
return ret;
}
n += ret;
if (ret < (ssize_t)to_read) {
D(VERBOSE, "bulk_read short read, ret=%zd to_read=%u n=%u length=%u",
ret, to_read, n, length);
break;
}
}
return n;
}
ssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
{
ssize_t ret;
struct transport *t = thandle->transport;
struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
D(DEBUG, "about to read (fd=%d, len=%d)", usb_transport->bulk_out, len);
ret = bulk_read(usb_transport->bulk_out, data, len);
if (ret < 0) {
D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
return -1;
}
D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret);
return ret;
}
void usb_close(struct transport_handle *thandle)
{
int err;
struct transport *t = thandle->transport;
struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT);
if (err < 0)
D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno);
err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT);
if (err < 0)
D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno);
pthread_mutex_lock(&usb_transport->lock);
close(usb_transport->control);
close(usb_transport->bulk_out);
close(usb_transport->bulk_in);
usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1;
pthread_cond_signal(&usb_transport->notify);
pthread_mutex_unlock(&usb_transport->lock);
}
struct transport_handle *usb_connect(struct transport *transport)
{
int ret;
struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1);
struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport);
pthread_mutex_lock(&usb_transport->lock);
while (usb_transport->control != -1)
pthread_cond_wait(&usb_transport->notify, &usb_transport->lock);
pthread_mutex_unlock(&usb_transport->lock);
ret = init_functionfs(usb_transport);
if (ret < 0) {
D(ERR, "usb connect: failed to initialize usb transport");
return NULL;
}
D(DEBUG, "[ usb_thread - registering device ]");
return &usb_handle->handle;
}
void usb_init()
{
struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport));
usb_transport->transport.connect = usb_connect;
usb_transport->transport.close = usb_close;
usb_transport->transport.read = usb_read;
usb_transport->transport.write = usb_write;
usb_transport->control = -1;
usb_transport->bulk_out = -1;
usb_transport->bulk_out = -1;
pthread_cond_init(&usb_transport->notify, NULL);
pthread_mutex_init(&usb_transport->lock, NULL);
transport_register(&usb_transport->transport);
}

View file

@ -3,12 +3,13 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= fs_mgr.c
LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_MODULE:= libfs_mgr
LOCAL_STATIC_LIBRARIES := liblogwrap
LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
@ -28,7 +29,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc
LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
include $(BUILD_EXECUTABLE)

View file

@ -27,18 +27,35 @@
#include <sys/wait.h>
#include <libgen.h>
#include <time.h>
#include <sys/swap.h>
/* XXX These need to be obtained from kernel headers. See b/9336527 */
#define SWAP_FLAG_PREFER 0x8000
#define SWAP_FLAG_PRIO_MASK 0x7fff
#define SWAP_FLAG_PRIO_SHIFT 0
#define SWAP_FLAG_DISCARD 0x10000
#include <linux/loop.h>
#include <private/android_filesystem_config.h>
#include <cutils/partition_utils.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
#define E2FSCK_BIN "/system/bin/e2fsck"
#define MKSWAP_BIN "/system/bin/mkswap"
#define FSCK_LOG_FILE "/dev/fscklogs/log"
#define ZRAM_CONF_DEV "/sys/block/zram0/disksize"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@ -74,10 +91,23 @@ static struct flag_list fs_mgr_flags[] = {
{ "voldmanaged=",MF_VOLDMANAGED},
{ "length=", MF_LENGTH },
{ "recoveryonly",MF_RECOVERYONLY },
{ "swapprio=", MF_SWAPPRIO },
{ "zramsize=", MF_ZRAMSIZE },
{ "verify", MF_VERIFY },
{ "noemulatedsd", MF_NOEMULATEDSD },
{ "defaults", 0 },
{ 0, 0 },
};
struct fs_mgr_flag_values {
char *key_loc;
long long part_length;
char *label;
int partnum;
int swap_prio;
unsigned int zram_size;
};
/*
* gettime() - returns the time in seconds of the system's monotonic clock or
* zero on error.
@ -109,7 +139,7 @@ static int wait_for_file(const char *filename, int timeout)
}
static int parse_flags(char *flags, struct flag_list *fl,
char **key_loc, long long *part_length, char **label, int *partnum,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
{
int f = 0;
@ -117,21 +147,12 @@ static int parse_flags(char *flags, struct flag_list *fl,
char *p;
char *savep;
/* initialize key_loc to null, if we find an MF_CRYPT flag,
* then we'll set key_loc to the proper value */
if (key_loc) {
*key_loc = NULL;
}
/* initialize part_length to 0, if we find an MF_LENGTH flag,
* then we'll set part_length to the proper value */
if (part_length) {
*part_length = 0;
}
if (partnum) {
*partnum = -1;
}
if (label) {
*label = NULL;
/* initialize flag values. If we find a relevant flag, we'll
* update the value */
if (flag_vals) {
memset(flag_vals, 0, sizeof(*flag_vals));
flag_vals->partnum = -1;
flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
}
/* initialize fs_options to the null string */
@ -147,17 +168,17 @@ static int parse_flags(char *flags, struct flag_list *fl,
for (i = 0; fl[i].name; i++) {
if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
f |= fl[i].flag;
if ((fl[i].flag == MF_CRYPT) && key_loc) {
if ((fl[i].flag == MF_CRYPT) && flag_vals) {
/* The encryptable flag is followed by an = and the
* location of the keys. Get it and return it.
*/
*key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && part_length) {
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
*/
*part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
/* The voldmanaged flag is followed by an = and the
* label, a colon and the partition number or the
* word "auto", e.g.
@ -171,17 +192,21 @@ static int parse_flags(char *flags, struct flag_list *fl,
label_start = strchr(p, '=') + 1;
label_end = strchr(p, ':');
if (label_end) {
*label = strndup(label_start,
(int) (label_end - label_start));
flag_vals->label = strndup(label_start,
(int) (label_end - label_start));
part_start = strchr(p, ':') + 1;
if (!strcmp(part_start, "auto")) {
*partnum = -1;
flag_vals->partnum = -1;
} else {
*partnum = strtol(part_start, NULL, 0);
flag_vals->partnum = strtol(part_start, NULL, 0);
}
} else {
ERROR("Warning: voldmanaged= flag malformed\n");
}
} else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
}
break;
}
@ -224,10 +249,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
char *save_ptr, *p;
struct fstab *fstab = NULL;
struct fstab_rec *recs;
char *key_loc;
long long part_length;
char *label;
int partnum;
struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
char tmp_fs_options[FS_OPTIONS_LEN];
@ -315,8 +337,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
goto err;
}
tmp_fs_options[0] = '\0';
fstab->recs[cnt].flags = parse_flags(p, mount_flags,
NULL, NULL, NULL, NULL,
fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
tmp_fs_options, FS_OPTIONS_LEN);
/* fs_options are optional */
@ -331,13 +352,13 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
goto err;
}
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
&key_loc, &part_length,
&label, &partnum,
NULL, 0);
fstab->recs[cnt].key_loc = key_loc;
fstab->recs[cnt].length = part_length;
fstab->recs[cnt].label = label;
fstab->recs[cnt].partnum = partnum;
&flag_vals, NULL, 0);
fstab->recs[cnt].key_loc = flag_vals.key_loc;
fstab->recs[cnt].length = flag_vals.part_length;
fstab->recs[cnt].label = flag_vals.label;
fstab->recs[cnt].partnum = flag_vals.partnum;
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
cnt++;
}
fclose(fstab_file);
@ -356,6 +377,10 @@ void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;
if (!fstab) {
return;
}
for (i = 0; i < fstab->num_entries; i++) {
/* Free the pointers return by strdup(3) */
free(fstab->recs[i].blk_device);
@ -411,7 +436,8 @@ static void check_fs(char *blk_device, char *fs_type, char *target)
INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
&status, true, LOG_KLOG, true);
&status, true, LOG_KLOG | LOG_FILE,
true, FSCK_LOG_FILE);
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
@ -433,6 +459,43 @@ static void remove_trailing_slashes(char *n)
}
}
/*
* Mark the given block device as read-only, using the BLKROSET ioctl.
* Return 0 on success, and -1 on error.
*/
static void fs_set_blk_ro(const char *blockdev)
{
int fd;
int ON = 1;
fd = open(blockdev, O_RDONLY);
if (fd < 0) {
// should never happen
return;
}
ioctl(fd, BLKROSET, &ON);
close(fd);
}
/*
* __mount(): wrapper around the mount() system call which also
* sets the underlying block device to read-only if the mount is read-only.
* See "man 2 mount" for return values.
*/
static int __mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data)
{
int ret = mount(source, target, filesystemtype, mountflags, data);
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_set_blk_ro(source);
}
return ret;
}
static int fs_match(char *in1, char *in2)
{
char *n1;
@ -470,8 +533,9 @@ int fs_mgr_mount_all(struct fstab *fstab)
continue;
}
/* Skip raw partition entries such as boot, recovery, etc */
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
/* Skip swap and raw partition entries such as boot, recovery, etc */
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
!strcmp(fstab->recs[i].fs_type, "emmc") ||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
continue;
}
@ -485,9 +549,17 @@ int fs_mgr_mount_all(struct fstab *fstab)
fstab->recs[i].mount_point);
}
mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
ERROR("Could not set up verified partition, skipping!");
continue;
}
}
mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
fstab->recs[i].fs_type, fstab->recs[i].flags,
fstab->recs[i].fs_options);
if (!mret) {
/* Success! Go get the next one */
continue;
@ -543,8 +615,9 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
}
/* We found our match */
/* If this is a raw partition, report an error */
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
/* If this swap or a raw partition, report an error */
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
!strcmp(fstab->recs[i].fs_type, "emmc") ||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
ERROR("Cannot mount filesystem of type %s on %s\n",
fstab->recs[i].fs_type, n_blk_device);
@ -561,14 +634,21 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
fstab->recs[i].mount_point);
}
if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
ERROR("Could not set up verified partition, skipping!");
continue;
}
}
/* Now mount it where requested */
if (tmp_mount_point) {
m = tmp_mount_point;
} else {
m = fstab->recs[i].mount_point;
}
if (mount(n_blk_device, m, fstab->recs[i].fs_type,
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
ERROR("Cannot mount filesystem on %s at %s\n",
n_blk_device, m);
goto out;
@ -623,6 +703,83 @@ int fs_mgr_unmount_all(struct fstab *fstab)
return ret;
}
/* This must be called after mount_all, because the mkswap command needs to be
* available.
*/
int fs_mgr_swapon_all(struct fstab *fstab)
{
int i = 0;
int flags = 0;
int err = 0;
int ret = 0;
int status;
char *mkswap_argv[2] = {
MKSWAP_BIN,
NULL
};
if (!fstab) {
return -1;
}
for (i = 0; i < fstab->num_entries; i++) {
/* Skip non-swap entries */
if (strcmp(fstab->recs[i].fs_type, "swap")) {
continue;
}
if (fstab->recs[i].zram_size > 0) {
/* A zram_size was specified, so we need to configure the
* device. There is no point in having multiple zram devices
* on a system (all the memory comes from the same pool) so
* we can assume the device number is 0.
*/
FILE *zram_fp;
zram_fp = fopen(ZRAM_CONF_DEV, "r+");
if (zram_fp == NULL) {
ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
ret = -1;
continue;
}
fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
fclose(zram_fp);
}
if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
/* Initialize the swap area */
mkswap_argv[1] = fstab->recs[i].blk_device;
err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
&status, true, LOG_KLOG, false, NULL);
if (err) {
ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
ret = -1;
continue;
}
/* If -1, then no priority was specified in fstab, so don't set
* SWAP_FLAG_PREFER or encode the priority */
if (fstab->recs[i].swap_prio >= 0) {
flags = (fstab->recs[i].swap_prio << SWAP_FLAG_PRIO_SHIFT) &
SWAP_FLAG_PRIO_MASK;
flags |= SWAP_FLAG_PREFER;
} else {
flags = 0;
}
err = swapon(fstab->recs[i].blk_device, flags);
if (err) {
ERROR("swapon failed for %s\n", fstab->recs[i].blk_device);
ret = -1;
}
}
return ret;
}
/*
* key_loc must be at least PROPERTY_VALUE_MAX bytes long
*
@ -729,3 +886,7 @@ int fs_mgr_is_encryptable(struct fstab_rec *fstab)
return fstab->fs_mgr_flags & MF_CRYPT;
}
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
}

View file

@ -69,6 +69,17 @@
#define MF_VOLDMANAGED 0x10
#define MF_LENGTH 0x20
#define MF_RECOVERYONLY 0x40
#define MF_SWAPPRIO 0x80
#define MF_ZRAMSIZE 0x100
#define MF_VERIFY 0x200
/*
* There is no emulated sdcard daemon running on /data/media on this device,
* so treat the physical SD card as the only external storage device,
* a la the Nexus One.
*/
#define MF_NOEMULATEDSD 0x400
#define DM_BUF_SIZE 4096
#endif /* __CORE_FS_MGR_PRIV_H */

View file

@ -0,0 +1,17 @@
/*
* Copyright (C) 2013 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.
*/
int fs_mgr_setup_verity(struct fstab_rec *fstab);

410
fs_mgr/fs_mgr_verity.c Normal file
View file

@ -0,0 +1,410 @@
/*
* Copyright (C) 2013 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <libgen.h>
#include <time.h>
#include <private/android_filesystem_config.h>
#include <logwrap/logwrap.h>
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
#include "ext4_utils.h"
#include "ext4.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"
#define VERITY_METADATA_SIZE 32768
#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
#define VERITY_TABLE_RSA_KEY "/verity_key"
extern struct fs_info info;
static RSAPublicKey *load_key(char *path)
{
FILE *f;
RSAPublicKey *key;
key = malloc(sizeof(RSAPublicKey));
if (!key) {
ERROR("Can't malloc key\n");
return NULL;
}
f = fopen(path, "r");
if (!f) {
ERROR("Can't open '%s'\n", path);
free(key);
return NULL;
}
if (!fread(key, sizeof(*key), 1, f)) {
ERROR("Could not read key!");
fclose(f);
free(key);
return NULL;
}
if (key->len != RSANUMWORDS) {
ERROR("Invalid key length %d\n", key->len);
fclose(f);
free(key);
return NULL;
}
fclose(f);
return key;
}
static int verify_table(char *signature, char *table, int table_length)
{
int fd;
RSAPublicKey *key;
uint8_t hash_buf[SHA_DIGEST_SIZE];
int retval = -1;
// Hash the table
SHA_hash((uint8_t*)table, table_length, hash_buf);
// Now get the public key from the keyfile
key = load_key(VERITY_TABLE_RSA_KEY);
if (!key) {
ERROR("Couldn't load verity keys");
goto out;
}
// verify the result
if (!RSA_verify(key,
(uint8_t*) signature,
RSANUMBYTES,
(uint8_t*) hash_buf,
SHA_DIGEST_SIZE)) {
ERROR("Couldn't verify table.");
goto out;
}
retval = 0;
out:
free(key);
return retval;
}
static int get_target_device_size(char *blk_device, uint64_t *device_size)
{
int data_device;
struct ext4_super_block sb;
data_device = open(blk_device, O_RDONLY);
if (data_device < 0) {
ERROR("Error opening block device (%s)", strerror(errno));
return -1;
}
if (lseek64(data_device, 1024, SEEK_SET) < 0) {
ERROR("Error seeking to superblock");
close(data_device);
return -1;
}
if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
ERROR("Error reading superblock");
close(data_device);
return -1;
}
ext4_parse_sb(&sb);
*device_size = info.len;
close(data_device);
return 0;
}
static int read_verity_metadata(char *block_device, char **signature, char **table)
{
unsigned magic_number;
unsigned table_length;
uint64_t device_length;
int protocol_version;
FILE *device;
int retval = -1;
device = fopen(block_device, "r");
if (!device) {
ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno));
goto out;
}
// find the start of the verity metadata
if (get_target_device_size(block_device, &device_length) < 0) {
ERROR("Could not get target device size.\n");
goto out;
}
if (fseek(device, device_length, SEEK_SET) < 0) {
ERROR("Could not seek to start of verity metadata block.\n");
goto out;
}
// check the magic number
if (!fread(&magic_number, sizeof(int), 1, device)) {
ERROR("Couldn't read magic number!\n");
goto out;
}
if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
ERROR("Couldn't find verity metadata at offset %llu!\n", device_length);
goto out;
}
// check the protocol version
if (!fread(&protocol_version, sizeof(int), 1, device)) {
ERROR("Couldn't read verity metadata protocol version!\n");
goto out;
}
if (protocol_version != 0) {
ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version);
goto out;
}
// get the signature
*signature = (char*) malloc(RSANUMBYTES * sizeof(char));
if (!*signature) {
ERROR("Couldn't allocate memory for signature!\n");
goto out;
}
if (!fread(*signature, RSANUMBYTES, 1, device)) {
ERROR("Couldn't read signature from verity metadata!\n");
free(*signature);
goto out;
}
// get the size of the table
if (!fread(&table_length, sizeof(int), 1, device)) {
ERROR("Couldn't get the size of the verity table from metadata!\n");
free(*signature);
goto out;
}
// get the table + null terminator
table_length += 1;
*table = malloc(table_length);
if(!*table) {
ERROR("Couldn't allocate memory for verity table!\n");
goto out;
}
if (!fgets(*table, table_length, device)) {
ERROR("Couldn't read the verity table from metadata!\n");
free(*table);
free(*signature);
goto out;
}
retval = 0;
out:
if (device)
fclose(device);
return retval;
}
static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
{
memset(io, 0, DM_BUF_SIZE);
io->data_size = DM_BUF_SIZE;
io->data_start = sizeof(struct dm_ioctl);
io->version[0] = 4;
io->version[1] = 0;
io->version[2] = 0;
io->flags = flags | DM_READONLY_FLAG;
if (name) {
strlcpy(io->name, name, sizeof(io->name));
}
}
static int create_verity_device(struct dm_ioctl *io, char *name, int fd)
{
verity_ioctl_init(io, name, 1);
if (ioctl(fd, DM_DEV_CREATE, io)) {
ERROR("Error creating device mapping (%s)", strerror(errno));
return -1;
}
return 0;
}
static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
{
verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_STATUS, io)) {
ERROR("Error fetching verity device number (%s)", strerror(errno));
return -1;
}
int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) {
ERROR("Error getting verity block device name (%s)", strerror(errno));
return -1;
}
return 0;
}
static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
{
char *verity_params;
char *buffer = (char*) io;
uint64_t device_size = 0;
if (get_target_device_size(blockdev, &device_size) < 0) {
return -1;
}
verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
// set tgt arguments here
io->target_count = 1;
tgt->status=0;
tgt->sector_start=0;
tgt->length=device_size/512;
strcpy(tgt->target_type, "verity");
// build the verity params here
verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
if (sprintf(verity_params, "%s", table) < 0) {
return -1;
}
// set next target boundary
verity_params += strlen(verity_params) + 1;
verity_params = (char*) (((unsigned long)verity_params + 7) & ~8);
tgt->next = verity_params - buffer;
// send the ioctl to load the verity table
if (ioctl(fd, DM_TABLE_LOAD, io)) {
ERROR("Error loading verity table (%s)", strerror(errno));
return -1;
}
return 0;
}
static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
{
verity_ioctl_init(io, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
ERROR("Error activating verity device (%s)", strerror(errno));
return -1;
}
return 0;
}
static int test_access(char *device) {
int tries = 25;
while (tries--) {
if (!access(device, F_OK) || errno != ENOENT) {
return 0;
}
usleep(40 * 1000);
}
return -1;
}
int fs_mgr_setup_verity(struct fstab_rec *fstab) {
int retval = -1;
char *verity_blk_name;
char *verity_table;
char *verity_table_signature;
char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
char *mount_point = basename(fstab->mount_point);
// set the dm_ioctl flags
io->flags |= 1;
io->target_count = 1;
// get the device mapper fd
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
ERROR("Error opening device mapper (%s)", strerror(errno));
return retval;
}
// create the device
if (create_verity_device(io, mount_point, fd) < 0) {
ERROR("Couldn't create verity device!");
goto out;
}
// get the name of the device file
if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
ERROR("Couldn't get verity device number!");
goto out;
}
// read the verity block at the end of the block device
if (read_verity_metadata(fstab->blk_device,
&verity_table_signature,
&verity_table) < 0) {
goto out;
}
// verify the signature on the table
if (verify_table(verity_table_signature,
verity_table,
strlen(verity_table)) < 0) {
goto out;
}
// load the verity mapping table
if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
goto out;
}
// activate the device
if (resume_verity_table(io, mount_point, fd) < 0) {
goto out;
}
// assign the new verity block device as the block device
free(fstab->blk_device);
fstab->blk_device = verity_blk_name;
// make sure we've set everything up properly
if (test_access(fstab->blk_device) < 0) {
goto out;
}
retval = 0;
out:
close(fd);
return retval;
}

View file

@ -17,6 +17,9 @@
#ifndef __CORE_FS_MGR_H
#define __CORE_FS_MGR_H
#include <stdint.h>
#include <linux/dm-ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -35,9 +38,12 @@ struct fstab_rec {
char *fs_options;
int fs_mgr_flags;
char *key_loc;
char *verity_loc;
long long length;
char *label;
int partnum;
int swap_prio;
unsigned int zram_size;
};
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
@ -56,6 +62,8 @@ struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const ch
int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
int fs_mgr_is_encryptable(struct fstab_rec *fstab);
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
#ifdef __cplusplus
}
#endif

30
healthd/Android.mk Normal file
View file

@ -0,0 +1,30 @@
# Copyright 2013 The Android Open Source Project
ifneq ($(BUILD_TINY_ANDROID),true)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := healthd_board_default.cpp
LOCAL_MODULE := libhealthd.default
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
healthd.cpp \
BatteryMonitor.cpp \
BatteryPropertiesRegistrar.cpp
LOCAL_MODULE := healthd
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc
LOCAL_HAL_STATIC_LIBRARIES := libhealthd
include $(BUILD_EXECUTABLE)
endif

424
healthd/BatteryMonitor.cpp Normal file
View file

@ -0,0 +1,424 @@
/*
* Copyright (C) 2013 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 "healthd"
#include "healthd.h"
#include "BatteryMonitor.h"
#include "BatteryPropertiesRegistrar.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#define POWER_SUPPLY_SUBSYSTEM "power_supply"
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
namespace android {
struct sysfsStringEnumMap {
char* s;
int val;
};
static int mapSysfsString(const char* str,
struct sysfsStringEnumMap map[]) {
for (int i = 0; map[i].s; i++)
if (!strcmp(str, map[i].s))
return map[i].val;
return -1;
}
int BatteryMonitor::getBatteryStatus(const char* status) {
int ret;
struct sysfsStringEnumMap batteryStatusMap[] = {
{ "Unknown", BATTERY_STATUS_UNKNOWN },
{ "Charging", BATTERY_STATUS_CHARGING },
{ "Discharging", BATTERY_STATUS_DISCHARGING },
{ "Not charging", BATTERY_STATUS_NOT_CHARGING },
{ "Full", BATTERY_STATUS_FULL },
{ NULL, 0 },
};
ret = mapSysfsString(status, batteryStatusMap);
if (ret < 0) {
KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
ret = BATTERY_STATUS_UNKNOWN;
}
return ret;
}
int BatteryMonitor::getBatteryHealth(const char* status) {
int ret;
struct sysfsStringEnumMap batteryHealthMap[] = {
{ "Unknown", BATTERY_HEALTH_UNKNOWN },
{ "Good", BATTERY_HEALTH_GOOD },
{ "Overheat", BATTERY_HEALTH_OVERHEAT },
{ "Dead", BATTERY_HEALTH_DEAD },
{ "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE },
{ "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE },
{ "Cold", BATTERY_HEALTH_COLD },
{ NULL, 0 },
};
ret = mapSysfsString(status, batteryHealthMap);
if (ret < 0) {
KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
ret = BATTERY_HEALTH_UNKNOWN;
}
return ret;
}
int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) {
char *cp = NULL;
if (path.isEmpty())
return -1;
int fd = open(path.string(), O_RDONLY, 0);
if (fd == -1) {
KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string());
return -1;
}
ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size));
if (count > 0)
cp = (char *)memrchr(buf, '\n', count);
if (cp)
*cp = '\0';
else
buf[0] = '\0';
close(fd);
return count;
}
BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
const int SIZE = 128;
char buf[SIZE];
int length = readFromFile(path, buf, SIZE);
BatteryMonitor::PowerSupplyType ret;
struct sysfsStringEnumMap supplyTypeMap[] = {
{ "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
{ "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
{ "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
{ "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS },
{ NULL, 0 },
};
if (length <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
if (ret < 0)
ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
return ret;
}
bool BatteryMonitor::getBooleanField(const String8& path) {
const int SIZE = 16;
char buf[SIZE];
bool value = false;
if (readFromFile(path, buf, SIZE) > 0) {
if (buf[0] != '0') {
value = true;
}
}
return value;
}
int BatteryMonitor::getIntField(const String8& path) {
const int SIZE = 128;
char buf[SIZE];
int value = 0;
if (readFromFile(path, buf, SIZE) > 0) {
value = strtol(buf, NULL, 0);
}
return value;
}
bool BatteryMonitor::update(void) {
struct BatteryProperties props;
bool logthis;
props.chargerAcOnline = false;
props.chargerUsbOnline = false;
props.chargerWirelessOnline = false;
props.batteryStatus = BATTERY_STATUS_UNKNOWN;
props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
props.batteryCurrentNow = INT_MIN;
props.batteryChargeCounter = INT_MIN;
if (!mHealthdConfig->batteryPresentPath.isEmpty())
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
else
props.batteryPresent = true;
props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);
if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath);
const int SIZE = 128;
char buf[SIZE];
String8 btech;
if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
props.batteryStatus = getBatteryStatus(buf);
if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
props.batteryHealth = getBatteryHealth(buf);
if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
props.batteryTechnology = String8(buf);
unsigned int i;
for (i = 0; i < mChargerNames.size(); i++) {
String8 path;
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
if (readFromFile(path, buf, SIZE) > 0) {
if (buf[0] != '0') {
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
props.chargerAcOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_USB:
props.chargerUsbOnline = true;
break;
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
props.chargerWirelessOnline = true;
break;
default:
KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
mChargerNames[i].string());
}
}
}
}
logthis = !healthd_board_battery_update(&props);
if (logthis) {
char dmesgline[256];
snprintf(dmesgline, sizeof(dmesgline),
"battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltage,
props.batteryTemperature < 0 ? "-" : "",
abs(props.batteryTemperature / 10),
abs(props.batteryTemperature % 10), props.batteryHealth,
props.batteryStatus);
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
char b[20];
snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
strlcat(dmesgline, b, sizeof(dmesgline));
}
KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
props.chargerAcOnline ? "a" : "",
props.chargerUsbOnline ? "u" : "",
props.chargerWirelessOnline ? "w" : "");
}
if (mBatteryPropertiesRegistrar != NULL)
mBatteryPropertiesRegistrar->notifyListeners(props);
return props.chargerAcOnline | props.chargerUsbOnline |
props.chargerWirelessOnline;
}
void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
String8 path;
mHealthdConfig = hc;
DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
if (dir == NULL) {
KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
} else {
struct dirent* entry;
while ((entry = readdir(dir))) {
const char* name = entry->d_name;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
char buf[20];
// Look for "type" file in each subdirectory
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
case ANDROID_POWER_SUPPLY_TYPE_USB:
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
if (access(path.string(), R_OK) == 0)
mChargerNames.add(String8(name));
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
if (mHealthdConfig->batteryStatusPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryStatusPath = path;
}
if (mHealthdConfig->batteryHealthPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryHealthPath = path;
}
if (mHealthdConfig->batteryPresentPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryPresentPath = path;
}
if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCapacityPath = path;
}
if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/voltage_now",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0) {
mHealthdConfig->batteryVoltagePath = path;
} else {
path.clear();
path.appendFormat("%s/%s/batt_vol",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryVoltagePath = path;
}
}
if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/current_now",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCurrentNowPath = path;
}
if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/charge_counter",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryChargeCounterPath = path;
}
if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0) {
mHealthdConfig->batteryTemperaturePath = path;
} else {
path.clear();
path.appendFormat("%s/%s/batt_temp",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryTemperaturePath = path;
}
}
if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/technology",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryTechnologyPath = path;
}
break;
case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
break;
}
}
closedir(dir);
}
if (!mChargerNames.size())
KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
if (mHealthdConfig->batteryStatusPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
if (mHealthdConfig->batteryHealthPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
if (mHealthdConfig->batteryPresentPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
if (mHealthdConfig->batteryCapacityPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
if (mHealthdConfig->batteryVoltagePath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
if (mHealthdConfig->batteryTemperaturePath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
if (mHealthdConfig->batteryTechnologyPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
if (nosvcmgr == false) {
mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
mBatteryPropertiesRegistrar->publish();
}
}
}; // namespace android

61
healthd/BatteryMonitor.h Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 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 HEALTHD_BATTERYMONITOR_H
#define HEALTHD_BATTERYMONITOR_H
#include <binder/IInterface.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include "healthd.h"
#include "BatteryPropertiesRegistrar.h"
namespace android {
class BatteryPropertiesRegistrar;
class BatteryMonitor {
public:
enum PowerSupplyType {
ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
ANDROID_POWER_SUPPLY_TYPE_AC,
ANDROID_POWER_SUPPLY_TYPE_USB,
ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
ANDROID_POWER_SUPPLY_TYPE_BATTERY
};
void init(struct healthd_config *hc, bool nosvcmgr);
bool update(void);
private:
struct healthd_config *mHealthdConfig;
Vector<String8> mChargerNames;
sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar;
int getBatteryStatus(const char* status);
int getBatteryHealth(const char* status);
int readFromFile(const String8& path, char* buf, size_t size);
PowerSupplyType readPowerSupplyType(const String8& path);
bool getBooleanField(const String8& path);
int getIntField(const String8& path);
};
}; // namespace android
#endif // HEALTHD_BATTERY_MONTIOR_H

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2013 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 "BatteryPropertiesRegistrar.h"
#include <batteryservice/BatteryService.h>
#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
#include <binder/IServiceManager.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/String16.h>
namespace android {
BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
mBatteryMonitor = monitor;
}
void BatteryPropertiesRegistrar::publish() {
defaultServiceManager()->addService(String16("batterypropreg"), this);
}
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
mListeners[i]->batteryPropertiesChanged(props);
}
}
void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
{
Mutex::Autolock _l(mRegistrationLock);
// check whether this is a duplicate
for (size_t i = 0; i < mListeners.size(); i++) {
if (mListeners[i]->asBinder() == listener->asBinder()) {
return;
}
}
mListeners.add(listener);
listener->asBinder()->linkToDeath(this);
}
mBatteryMonitor->update();
}
void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
if (mListeners[i]->asBinder() == listener->asBinder()) {
mListeners[i]->asBinder()->unlinkToDeath(this);
mListeners.removeAt(i);
break;
}
}
}
void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
if (mListeners[i]->asBinder() == who) {
mListeners.removeAt(i);
break;
}
}
}
} // namespace android

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2013 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 HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
#include "BatteryMonitor.h"
#include <binder/IBinder.h>
#include <utils/Mutex.h>
#include <utils/Vector.h>
#include <batteryservice/BatteryService.h>
#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
namespace android {
class BatteryMonitor;
class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
public IBinder::DeathRecipient {
public:
BatteryPropertiesRegistrar(BatteryMonitor* monitor);
void publish();
void notifyListeners(struct BatteryProperties props);
private:
BatteryMonitor* mBatteryMonitor;
Mutex mRegistrationLock;
Vector<sp<IBatteryPropertiesListener> > mListeners;
void registerListener(const sp<IBatteryPropertiesListener>& listener);
void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
void binderDied(const wp<IBinder>& who);
};
}; // namespace android
#endif // HEALTHD_BATTERYPROPERTIES_REGISTRAR_H

285
healthd/healthd.cpp Normal file
View file

@ -0,0 +1,285 @@
/*
* Copyright (C) 2013 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 "healthd"
#define KLOG_LEVEL 6
#include "healthd.h"
#include "BatteryMonitor.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <batteryservice/BatteryService.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <cutils/klog.h>
#include <cutils/uevent.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
using namespace android;
// Periodic chores intervals in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
static struct healthd_config healthd_config = {
.periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
.periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
.batteryStatusPath = String8(String8::kEmptyString),
.batteryHealthPath = String8(String8::kEmptyString),
.batteryPresentPath = String8(String8::kEmptyString),
.batteryCapacityPath = String8(String8::kEmptyString),
.batteryVoltagePath = String8(String8::kEmptyString),
.batteryTemperaturePath = String8(String8::kEmptyString),
.batteryTechnologyPath = String8(String8::kEmptyString),
.batteryCurrentNowPath = String8(String8::kEmptyString),
.batteryChargeCounterPath = String8(String8::kEmptyString),
};
#define POWER_SUPPLY_SUBSYSTEM "power_supply"
// epoll events: uevent, wakealarm, binder
#define MAX_EPOLL_EVENTS 3
static int uevent_fd;
static int wakealarm_fd;
static int binder_fd;
// -1 for no epoll timeout
static int awake_poll_interval = -1;
static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
static BatteryMonitor* gBatteryMonitor;
static bool nosvcmgr;
static void wakealarm_set_interval(int interval) {
struct itimerspec itval;
if (wakealarm_fd == -1)
return;
wakealarm_wake_interval = interval;
if (interval == -1)
interval = 0;
itval.it_interval.tv_sec = interval;
itval.it_interval.tv_nsec = 0;
itval.it_value.tv_sec = interval;
itval.it_value.tv_nsec = 0;
if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
}
static void battery_update(void) {
// Fast wake interval when on charger (watch for overheat);
// slow wake interval when on battery (watch for drained battery).
int new_wake_interval = gBatteryMonitor->update() ?
healthd_config.periodic_chores_interval_fast :
healthd_config.periodic_chores_interval_slow;
if (new_wake_interval != wakealarm_wake_interval)
wakealarm_set_interval(new_wake_interval);
// During awake periods poll at fast rate. If wake alarm is set at fast
// rate then just use the alarm; if wake alarm is set at slow rate then
// poll at fast rate while awake and let alarm wake up at slow rate when
// asleep.
if (healthd_config.periodic_chores_interval_fast == -1)
awake_poll_interval = -1;
else
awake_poll_interval =
new_wake_interval == healthd_config.periodic_chores_interval_fast ?
-1 : healthd_config.periodic_chores_interval_fast * 1000;
}
static void periodic_chores() {
battery_update();
}
static void uevent_init(void) {
uevent_fd = uevent_open_socket(64*1024, true);
if (uevent_fd >= 0)
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
else
KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
}
#define UEVENT_MSG_LEN 1024
static void uevent_event(void) {
char msg[UEVENT_MSG_LEN+2];
char *cp;
int n;
n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0)
return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n+1] = '\0';
cp = msg;
while (*cp) {
if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
battery_update();
break;
}
/* advance to after the next \0 */
while (*cp++)
;
}
}
static void wakealarm_init(void) {
wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
if (wakealarm_fd == -1) {
KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
return;
}
wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}
static void wakealarm_event(void) {
unsigned long long wakeups;
if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm_fd failed\n");
return;
}
periodic_chores();
}
static void binder_init(void) {
ProcessState::self()->setThreadPoolMaxThreadCount(0);
IPCThreadState::self()->disableBackgroundScheduling(true);
IPCThreadState::self()->setupPolling(&binder_fd);
}
static void binder_event(void) {
IPCThreadState::self()->handlePolledCommands();
}
static void healthd_mainloop(void) {
struct epoll_event ev;
int epollfd;
int maxevents = 0;
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1) {
KLOG_ERROR(LOG_TAG,
"healthd_mainloop: epoll_create failed; errno=%d\n",
errno);
return;
}
if (uevent_fd >= 0) {
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)uevent_event;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
KLOG_ERROR(LOG_TAG,
"healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
errno);
else
maxevents++;
}
if (wakealarm_fd >= 0) {
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)wakealarm_event;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
KLOG_ERROR(LOG_TAG,
"healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
errno);
else
maxevents++;
}
if (binder_fd >= 0) {
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr= (void *)binder_event;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
KLOG_ERROR(LOG_TAG,
"healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
errno);
else
maxevents++;
}
while (1) {
struct epoll_event events[maxevents];
int nevents;
IPCThreadState::self()->flushCommands();
nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);
if (nevents == -1) {
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)())events[n].data.ptr)();
}
if (!nevents)
periodic_chores();
}
return;
}
int main(int argc, char **argv) {
int ch;
klog_set_level(KLOG_LEVEL);
while ((ch = getopt(argc, argv, "n")) != -1) {
switch (ch) {
case 'n':
nosvcmgr = true;
break;
case '?':
default:
KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
}
}
healthd_board_init(&healthd_config);
wakealarm_init();
uevent_init();
binder_init();
gBatteryMonitor = new BatteryMonitor();
gBatteryMonitor->init(&healthd_config, nosvcmgr);
healthd_mainloop();
return 0;
}

92
healthd/healthd.h Normal file
View file

@ -0,0 +1,92 @@
/*
* Copyright (C) 2013 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 _HEALTHD_H_
#define _HEALTHD_H_
#include <batteryservice/BatteryService.h>
#include <utils/String8.h>
// periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
// which healthd wakes up to poll health state and perform periodic chores,
// in units of seconds:
//
// periodic_chores_interval_fast is used while the device is not in
// suspend, or in suspend and connected to a charger (to watch for battery
// overheat due to charging). The default value is 60 (1 minute). Value
// -1 turns off periodic chores (and wakeups) in these conditions.
//
// periodic_chores_interval_slow is used when the device is in suspend and
// not connected to a charger (to watch for a battery drained to zero
// remaining capacity). The default value is 600 (10 minutes). Value -1
// tuns off periodic chores (and wakeups) in these conditions.
//
// power_supply sysfs attribute file paths. Set these to specific paths
// to use for the associated battery parameters. healthd will search for
// appropriate power_supply attribute files to use for any paths left empty:
//
// batteryStatusPath: charging status (POWER_SUPPLY_PROP_STATUS)
// batteryHealthPath: battery health (POWER_SUPPLY_PROP_HEALTH)
// batteryPresentPath: battery present (POWER_SUPPLY_PROP_PRESENT)
// batteryCapacityPath: remaining capacity (POWER_SUPPLY_PROP_CAPACITY)
// batteryVoltagePath: battery voltage (POWER_SUPPLY_PROP_VOLTAGE_NOW)
// batteryTemperaturePath: battery temperature (POWER_SUPPLY_PROP_TEMP)
// batteryTechnologyPath: battery technology (POWER_SUPPLY_PROP_TECHNOLOGY)
// batteryCurrentNowPath: battery current (POWER_SUPPLY_PROP_CURRENT_NOW)
// batteryChargeCounterPath: battery accumulated charge
// (POWER_SUPPLY_PROP_CHARGE_COUNTER)
struct healthd_config {
int periodic_chores_interval_fast;
int periodic_chores_interval_slow;
android::String8 batteryStatusPath;
android::String8 batteryHealthPath;
android::String8 batteryPresentPath;
android::String8 batteryCapacityPath;
android::String8 batteryVoltagePath;
android::String8 batteryTemperaturePath;
android::String8 batteryTechnologyPath;
android::String8 batteryCurrentNowPath;
android::String8 batteryChargeCounterPath;
};
// The following are implemented in libhealthd_board to handle board-specific
// behavior.
//
// healthd_board_init() is called at startup time to modify healthd's
// configuration according to board-specific requirements. config
// points to the healthd configuration values described above. To use default
// values, this function can simply return without modifying the fields of the
// config parameter.
void healthd_board_init(struct healthd_config *config);
// Process updated battery property values. This function is called when
// the kernel sends updated battery status via a uevent from the power_supply
// subsystem, or when updated values are polled by healthd, as for periodic
// poll of battery state.
//
// props are the battery properties read from the kernel. These values may
// be modified in this call, prior to sending the modified values to the
// Android runtime.
//
// Return 0 to indicate the usual kernel log battery status heartbeat message
// is to be logged, or non-zero to prevent logging this information.
int healthd_board_battery_update(struct android::BatteryProperties *props);
#endif /* _HEALTHD_H_ */

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (C) 2013 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.
@ -14,18 +14,16 @@
* limitations under the License.
*/
#ifndef __CUTILS_ZYGOTE_H
#define __CUTILS_ZYGOTE_H
#include <healthd.h>
#ifdef __cplusplus
extern "C" {
#endif
int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
int zygote_run(int argc, const char **argv);
#ifdef __cplusplus
void healthd_board_init(struct healthd_config *config)
{
// use defaults
}
#endif
#endif /* __CUTILS_ZYGOTE_H */
int healthd_board_battery_update(struct android::BatteryProperties *props)
{
// return 0 to log periodic polled battery status to kernel log
return 0;
}

View file

@ -1,103 +0,0 @@
/*
* Copyright 2009, 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.
*/
/* Helper to perform abortable blocking operations on a socket:
* asocket_connect()
* asocket_accept()
* asocket_read()
* asocket_write()
* These calls are similar to the regular syscalls, but can be aborted with:
* asocket_abort()
*
* Calling close() on a regular POSIX socket does not abort blocked syscalls on
* that socket in other threads.
*
* After calling asocket_abort() the socket cannot be reused.
*
* Call asocket_destory() *after* all threads have finished with the socket to
* finish closing the socket and free the asocket structure.
*
* The helper is implemented by setting the socket non-blocking to initiate
* syscalls connect(), accept(), read(), write(), then using a blocking poll()
* on both the primary socket and a local pipe. This makes the poll() abortable
* by writing a byte to the local pipe in asocket_abort().
*
* asocket_create() sets the fd to non-blocking mode. It must not be changed to
* blocking mode.
*
* Using asocket will triple the number of file descriptors required per
* socket, due to the local pipe. It may be possible to use a global pipe per
* process rather than per socket, but we have not been able to come up with a
* race-free implementation yet.
*
* All functions except asocket_init() and asocket_destroy() are thread safe.
*/
#include <stdlib.h>
#include <sys/socket.h>
#ifndef __CUTILS_ABORT_SOCKET_H__
#define __CUTILS_ABORT_SOCKET_H__
#ifdef __cplusplus
extern "C" {
#endif
struct asocket {
int fd; /* primary socket fd */
int abort_fd[2]; /* pipe used to abort */
};
/* Create an asocket from fd.
* Sets the socket to non-blocking mode.
* Returns NULL on error with errno set.
*/
struct asocket *asocket_init(int fd);
/* Blocking socket I/O with timeout.
* Calling asocket_abort() from another thread will cause each of these
* functions to immediately return with value -1 and errno ECANCELED.
* timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned
* with errno ETIMEDOUT.
* EINTR is handled in-call.
* Other semantics are identical to the regular syscalls.
*/
int asocket_connect(struct asocket *s, const struct sockaddr *addr,
socklen_t addrlen, int timeout);
int asocket_accept(struct asocket *s, struct sockaddr *addr,
socklen_t *addrlen, int timeout);
int asocket_read(struct asocket *s, void *buf, size_t count, int timeout);
int asocket_write(struct asocket *s, const void *buf, size_t count,
int timeout);
/* Abort above calls and shutdown socket.
* Further I/O operations on this socket will immediately fail after this call.
* asocket_destroy() should be used to release resources once all threads
* have returned from blocking calls on the socket.
*/
void asocket_abort(struct asocket *s);
/* Close socket and free asocket structure.
* Must not be called until all calls on this structure have completed.
*/
void asocket_destroy(struct asocket *s);
#ifdef __cplusplus
}
#endif
#endif //__CUTILS_ABORT_SOCKET__H__

View file

@ -24,9 +24,8 @@ __BEGIN_DECLS
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003
/* Flags */
#define ANDROID_RB_FLAG_NO_SYNC 0x1
#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
/* Properties */
#define ANDROID_RB_PROPERTY "sys.powerctl"
int android_reboot(int cmd, int flags, char *arg);

View file

@ -1,67 +0,0 @@
/*
* Copyright (C) 2007 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.
*/
/**
* A pointer array which intelligently expands its capacity ad needed.
*/
#ifndef __ARRAY_H
#define __ARRAY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/** An array. */
typedef struct Array Array;
/** Constructs a new array. Returns NULL if we ran out of memory. */
Array* arrayCreate();
/** Frees an array. Does not free elements themselves. */
void arrayFree(Array* array);
/** Adds a pointer. Returns 0 is successful, < 0 otherwise. */
int arrayAdd(Array* array, void* pointer);
/** Gets the pointer at the specified index. */
void* arrayGet(Array* array, int index);
/** Removes the pointer at the given index and returns it. */
void* arrayRemove(Array* array, int index);
/** Sets pointer at the given index. Returns old pointer. */
void* arraySet(Array* array, int index, void* pointer);
/** Sets the array size. Sets new pointers to NULL. Returns 0 if successful, < 0 otherwise . */
int arraySetSize(Array* array, int size);
/** Returns the size of the given array. */
int arraySize(Array* array);
/**
* Returns a pointer to a C-style array which will be valid until this array
* changes.
*/
const void** arrayUnwrap(Array* array);
#ifdef __cplusplus
}
#endif
#endif /* __ARRAY_H */

View file

@ -75,6 +75,16 @@ static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
return -1;
}
static inline int bitmask_weight(unsigned int *bitmask, int num_bits)
{
int i;
int weight = 0;
for (i = 0; i < BITS_TO_WORDS(num_bits); i++)
weight += __builtin_popcount(bitmask[i]);
return weight;
}
static inline void bitmask_set(unsigned int *bitmask, int bit)
{
bitmask[BIT_WORD(bit)] |= BIT_MASK(bit);

View file

@ -55,6 +55,14 @@ extern int fs_read_atomic_int(const char* path, int* value);
*/
extern int fs_write_atomic_int(const char* path, int value);
/*
* Ensure that all directories along given path exist, creating parent
* directories as needed. Validates that given path is absolute and that
* it contains no relative "." or ".." paths or symlinks. Last path segment
* is treated as filename and ignored, unless the path ends with "/".
*/
extern int fs_mkdirs(const char* path, mode_t mode);
#ifdef __cplusplus
}
#endif

View file

@ -1,563 +1 @@
/*
* Copyright (C) 2005 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.
*/
//
// C/C++ logging functions. See the logging documentation for API details.
//
// We'd like these to be available from C code (in case we import some from
// somewhere), so this has a C interface.
//
// The output will be correct when the log file is shared between multiple
// threads and/or multiple processes so long as the operating system
// supports O_APPEND. These calls have mutex-protected data structures
// and so are NOT reentrant. Do not use LOG in a signal handler.
//
#ifndef _LIBS_CUTILS_LOG_H
#define _LIBS_CUTILS_LOG_H
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif
#include <stdarg.h>
#include <cutils/uio.h>
#include <cutils/logd.h>
#ifdef __cplusplus
extern "C" {
#endif
// ---------------------------------------------------------------------
/*
* Normally we strip ALOGV (VERBOSE messages) from release builds.
* You can modify this (for example with "#define LOG_NDEBUG 0"
* at the top of your source file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
/*
* This is the local tag used for the following simplified
* logging macros. You can change this preprocessor definition
* before using the other macros to change the tag.
*/
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose log message using the current LOG_TAG.
*/
#ifndef ALOGV
#if LOG_NDEBUG
#define ALOGV(...) ((void)0)
#else
#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef ALOGV_IF
#if LOG_NDEBUG
#define ALOGV_IF(cond, ...) ((void)0)
#else
#define ALOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
/*
* Simplified macro to send a debug log message using the current LOG_TAG.
*/
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGD_IF
#define ALOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info log message using the current LOG_TAG.
*/
#ifndef ALOGI
#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGI_IF
#define ALOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning log message using the current LOG_TAG.
*/
#ifndef ALOGW
#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGW_IF
#define ALOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error log message using the current LOG_TAG.
*/
#ifndef ALOGE
#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGE_IF
#define ALOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
// ---------------------------------------------------------------------
/*
* Conditional based on whether the current LOG_TAG is enabled at
* verbose priority.
*/
#ifndef IF_ALOGV
#if LOG_NDEBUG
#define IF_ALOGV() if (false)
#else
#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
#endif
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* debug priority.
*/
#ifndef IF_ALOGD
#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* info priority.
*/
#ifndef IF_ALOGI
#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* warn priority.
*/
#ifndef IF_ALOGW
#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* error priority.
*/
#ifndef IF_ALOGE
#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose system log message using the current LOG_TAG.
*/
#ifndef SLOGV
#if LOG_NDEBUG
#define SLOGV(...) ((void)0)
#else
#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef SLOGV_IF
#if LOG_NDEBUG
#define SLOGV_IF(cond, ...) ((void)0)
#else
#define SLOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
/*
* Simplified macro to send a debug system log message using the current LOG_TAG.
*/
#ifndef SLOGD
#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGD_IF
#define SLOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info system log message using the current LOG_TAG.
*/
#ifndef SLOGI
#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGI_IF
#define SLOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning system log message using the current LOG_TAG.
*/
#ifndef SLOGW
#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGW_IF
#define SLOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error system log message using the current LOG_TAG.
*/
#ifndef SLOGE
#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGE_IF
#define SLOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose radio log message using the current LOG_TAG.
*/
#ifndef RLOGV
#if LOG_NDEBUG
#define RLOGV(...) ((void)0)
#else
#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef RLOGV_IF
#if LOG_NDEBUG
#define RLOGV_IF(cond, ...) ((void)0)
#else
#define RLOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
/*
* Simplified macro to send a debug radio log message using the current LOG_TAG.
*/
#ifndef RLOGD
#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGD_IF
#define RLOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info radio log message using the current LOG_TAG.
*/
#ifndef RLOGI
#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGI_IF
#define RLOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning radio log message using the current LOG_TAG.
*/
#ifndef RLOGW
#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGW_IF
#define RLOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error radio log message using the current LOG_TAG.
*/
#ifndef RLOGE
#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGE_IF
#define RLOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
// ---------------------------------------------------------------------
/*
* Log a fatal error. If the given condition fails, this stops program
* execution like a normal assertion, but also generating the given message.
* It is NOT stripped from release builds. Note that the condition test
* is -inverted- from the normal assert() semantics.
*/
#ifndef LOG_ALWAYS_FATAL_IF
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
: (void)0 )
#endif
#ifndef LOG_ALWAYS_FATAL
#define LOG_ALWAYS_FATAL(...) \
( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
#endif
/*
* Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
* are stripped out of release builds.
*/
#if LOG_NDEBUG
#ifndef LOG_FATAL_IF
#define LOG_FATAL_IF(cond, ...) ((void)0)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) ((void)0)
#endif
#else
#ifndef LOG_FATAL_IF
#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
#endif
#endif
/*
* Assertion that generates a log message when the assertion fails.
* Stripped out of release builds. Uses the current LOG_TAG.
*/
#ifndef ALOG_ASSERT
#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
#endif
// ---------------------------------------------------------------------
/*
* Basic log message macro.
*
* Example:
* ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
*
* The second argument may be NULL or "" to indicate the "global" tag.
*/
#ifndef ALOG
#define ALOG(priority, tag, ...) \
LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to specify a number for the priority.
*/
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
android_printLog(priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to pass in a varargs ("args" is a va_list).
*/
#ifndef LOG_PRI_VA
#define LOG_PRI_VA(priority, tag, fmt, args) \
android_vprintLog(priority, NULL, tag, fmt, args)
#endif
/*
* Conditional given a desired logging priority and tag.
*/
#ifndef IF_ALOG
#define IF_ALOG(priority, tag) \
if (android_testLog(ANDROID_##priority, tag))
#endif
// ---------------------------------------------------------------------
/*
* Event logging.
*/
/*
* Event log entry types. These must match up with the declarations in
* java/android/android/util/EventLog.java.
*/
typedef enum {
EVENT_TYPE_INT = 0,
EVENT_TYPE_LONG = 1,
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
} AndroidEventLogType;
#ifndef LOG_EVENT_INT
#define LOG_EVENT_INT(_tag, _value) { \
int intBuf = _value; \
(void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
sizeof(intBuf)); \
}
#endif
#ifndef LOG_EVENT_LONG
#define LOG_EVENT_LONG(_tag, _value) { \
long long longBuf = _value; \
(void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
sizeof(longBuf)); \
}
#endif
#ifndef LOG_EVENT_STRING
#define LOG_EVENT_STRING(_tag, _value) \
((void) 0) /* not implemented -- must combine len with string */
#endif
/* TODO: something for LIST */
/*
* ===========================================================================
*
* The stuff in the rest of this file should not be used directly.
*/
#define android_printLog(prio, tag, fmt...) \
__android_log_print(prio, tag, fmt)
#define android_vprintLog(prio, cond, tag, fmt...) \
__android_log_vprint(prio, tag, fmt)
/* XXX Macros to work around syntax errors in places where format string
* arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
* (happens only in debug builds).
*/
/* Returns 2nd arg. Used to substitute default value if caller's vararg list
* is empty.
*/
#define __android_second(dummy, second, ...) second
/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
* returns nothing.
*/
#define __android_rest(first, ...) , ## __VA_ARGS__
#define android_printAssert(cond, tag, fmt...) \
__android_log_assert(cond, tag, \
__android_second(0, ## fmt, NULL) __android_rest(fmt))
#define android_writeLog(prio, tag, text) \
__android_log_write(prio, tag, text)
#define android_bWriteLog(tag, payload, len) \
__android_log_bwrite(tag, payload, len)
#define android_btWriteLog(tag, type, payload, len) \
__android_log_btwrite(tag, type, payload, len)
// TODO: remove these prototypes and their users
#define android_testLog(prio, tag) (1)
#define android_writevLog(vec,num) do{}while(0)
#define android_write1Log(str,len) do{}while (0)
#define android_setMinPriority(tag, prio) do{}while(0)
//#define android_logToCallback(func) do{}while(0)
#define android_logToFile(tag, file) (0)
#define android_logToFd(tag, fd) (0)
typedef enum {
LOG_ID_MAIN = 0,
LOG_ID_RADIO = 1,
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_MAX
} log_id_t;
/*
* Send a simple string to the log.
*/
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif // _LIBS_CUTILS_LOG_H
#include <log/log.h>

View file

@ -1,124 +0,0 @@
/*
* Copyright (C) 2007 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.
*/
/**
* IPC messaging library.
*/
#ifndef __MQ_H
#define __MQ_H
#ifdef __cplusplus
extern "C" {
#endif
/** A message. */
typedef struct MqMessage MqMessage;
/** A destination to which messages can be sent. */
typedef struct MqDestination MqDestination;
/* Array of bytes. */
typedef struct MqBytes MqBytes;
/**
* Hears messages.
*
* @param destination to which the message was sent
* @param message the message to hear
*/
typedef void MqMessageListener(MqDestination* destination, MqMessage* message);
/**
* Hears a destination close.
*
* @param destination that closed
*/
typedef void MqCloseListener(MqDestination* destination);
/** Message functions. */
/**
* Creates a new Message.
*
* @param header as defined by user
* @param body as defined by user
* @param replyTo destination to which replies should be sent, NULL if none
*/
MqMessage* mqCreateMessage(MqBytes header, MqBytes body,
MqDestination* replyTo);
/** Sends a message to a destination. */
void mqSendMessage(MqMessage* message, MqDestination* destination);
/** Destination functions. */
/**
* Creates a new destination. Acquires a reference implicitly.
*
* @param messageListener function to call when a message is recieved
* @param closeListener function to call when the destination closes
* @param userData user-specific data to associate with the destination.
* Retrieve using mqGetDestinationUserData().
*/
MqDestination* mqCreateDestination(MqMessageListener* messageListener,
MqCloseListener* closeListener, void* userData);
/**
* Gets user data which was associated with the given destination at
* construction time.
*
* It is only valid to call this function in the same process that the
* given destination was created in.
* This function returns a null pointer if you call it on a destination
* created in a remote process.
*/
void* mqGetUserData(MqDestination* destination);
/**
* Returns 1 if the destination was created in this process, or 0 if
* the destination was created in a different process, in which case you have
* a remote stub.
*/
int mqIsDestinationLocal(MqDestination* destination);
/**
* Increments the destination's reference count.
*/
void mqKeepDestination(MqDesintation* destination);
/**
* Decrements the destination's reference count.
*/
void mqFreeDestination(MqDestination* desintation);
/** Registry API. */
/**
* Gets the destination bound to a name.
*/
MqDestination* mqGetDestination(char* name);
/**
* Binds a destination to a name.
*/
void mqPutDestination(char* name, MqDestination* desintation);
#ifdef __cplusplus
}
#endif
#endif /* __MQ_H */

View file

@ -17,6 +17,10 @@
#ifndef __CUTILS_PROPERTIES_H
#define __CUTILS_PROPERTIES_H
#include <sys/cdefs.h>
#include <stddef.h>
#include <sys/system_properties.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -28,8 +32,8 @@ extern "C" {
** WARNING: system/bionic/include/sys/system_properties.h also defines
** these, but with different names. (TODO: fix that)
*/
#define PROPERTY_KEY_MAX 32
#define PROPERTY_VALUE_MAX 92
#define PROPERTY_KEY_MAX PROP_NAME_MAX
#define PROPERTY_VALUE_MAX PROP_VALUE_MAX
/* property_get: returns the length of the value which will never be
** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
@ -46,6 +50,22 @@ int property_set(const char *key, const char *value);
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
#if defined(__BIONIC_FORTIFY)
extern int __property_get_real(const char *, char *, const char *)
__asm__(__USER_LABEL_PREFIX__ "property_get");
__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer");
__BIONIC_FORTIFY_INLINE
int property_get(const char *key, char *value, const char *default_value) {
size_t bos = __bos(value);
if (bos < PROPERTY_VALUE_MAX) {
__property_get_too_small_error();
}
return __property_get_real(key, value, default_value);
}
#endif
#ifdef HAVE_SYSTEM_PROPERTY_SERVER
/*

View file

@ -1,130 +0,0 @@
/*
* Copyright (C) 2007 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.
*/
/**
* Framework for multiplexing I/O. A selector manages a set of file
* descriptors and calls out to user-provided callback functions to read and
* write data and handle errors.
*/
#ifndef __SELECTOR_H
#define __SELECTOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
/**
* Manages SelectableFds and invokes their callbacks at appropriate times.
*/
typedef struct Selector Selector;
/**
* A selectable descriptor. Contains callbacks which the selector can invoke
* before calling select(), when the descriptor is readable or writable, and
* when the descriptor contains out-of-band data. Simply set a callback to
* NULL if you're not interested in that particular event.
*
* A selectable descriptor can indicate that it needs to be removed from the
* selector by setting the 'remove' flag. The selector will remove the
* descriptor at a later time and invoke the onRemove() callback.
*
* SelectableFd fields should only be modified from the selector loop.
*/
typedef struct SelectableFd SelectableFd;
struct SelectableFd {
/** The file descriptor itself. */
int fd;
/** Pointer to user-specific data. Can be NULL. */
void* data;
/**
* Set this flag when you no longer wish to be selected. The selector
* will invoke onRemove() when the descriptor is actually removed.
*/
bool remove;
/**
* Invoked by the selector before calling select. You can set up other
* callbacks from here as necessary.
*/
void (*beforeSelect)(SelectableFd* self);
/**
* Invoked by the selector when the descriptor has data available. Set to
* NULL to indicate that you're not interested in reading.
*/
void (*onReadable)(SelectableFd* self);
/**
* Invoked by the selector when the descriptor can accept data. Set to
* NULL to indicate that you're not interested in writing.
*/
void (*onWritable)(SelectableFd* self);
/**
* Invoked by the selector when out-of-band (OOB) data is available. Set to
* NULL to indicate that you're not interested in OOB data.
*/
void (*onExcept)(SelectableFd* self);
/**
* Invoked by the selector after the descriptor is removed from the
* selector but before the selector frees the SelectableFd memory.
*/
void (*onRemove)(SelectableFd* self);
/**
* The selector which selected this fd. Set by the selector itself.
*/
Selector* selector;
};
/**
* Creates a new selector.
*/
Selector* selectorCreate(void);
/**
* Creates a new selectable fd, adds it to the given selector and returns a
* pointer. Outside of 'selector' and 'fd', all fields are set to 0 or NULL
* by default.
*
* The selectable fd should only be modified from the selector loop thread.
*/
SelectableFd* selectorAdd(Selector* selector, int fd);
/**
* Wakes up the selector even though no I/O events occurred. Use this
* to indicate that you're ready to write to a descriptor.
*/
void selectorWakeUp(Selector* selector);
/**
* Loops continuously selecting file descriptors and firing events.
* Does not return.
*/
void selectorLoop(Selector* selector);
#ifdef __cplusplus
}
#endif
#endif /* __SELECTOR_H */

View file

@ -66,7 +66,8 @@ __BEGIN_DECLS
#define ATRACE_TAG_APP (1<<12)
#define ATRACE_TAG_RESOURCES (1<<13)
#define ATRACE_TAG_DALVIK (1<<14)
#define ATRACE_TAG_LAST ATRACE_TAG_DALVIK
#define ATRACE_TAG_RS (1<<15)
#define ATRACE_TAG_LAST ATRACE_TAG_RS
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1LL<<63)
@ -258,11 +259,28 @@ static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
}
}
/**
* Traces a 64-bit integer counter value. name is used to identify the
* counter. This can be used to track how a value changes over time.
*/
#define ATRACE_INT64(name, value) atrace_int64(ATRACE_TAG, name, value)
static inline void atrace_int64(uint64_t tag, const char* name, int64_t value)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%lld",
getpid(), name, value);
write(atrace_marker_fd, buf, len);
}
}
#else // not HAVE_ANDROID_OS
#define ATRACE_INIT()
#define ATRACE_GET_ENABLED_TAGS()
#define ATRACE_ENABLED()
#define ATRACE_ENABLED() 0
#define ATRACE_BEGIN(name)
#define ATRACE_END()
#define ATRACE_ASYNC_BEGIN(name, cookie)

563
include/log/log.h Normal file
View file

@ -0,0 +1,563 @@
/*
* Copyright (C) 2005 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.
*/
//
// C/C++ logging functions. See the logging documentation for API details.
//
// We'd like these to be available from C code (in case we import some from
// somewhere), so this has a C interface.
//
// The output will be correct when the log file is shared between multiple
// threads and/or multiple processes so long as the operating system
// supports O_APPEND. These calls have mutex-protected data structures
// and so are NOT reentrant. Do not use LOG in a signal handler.
//
#ifndef _LIBS_LOG_LOG_H
#define _LIBS_LOG_LOG_H
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif
#include <stdarg.h>
#include <log/uio.h>
#include <log/logd.h>
#ifdef __cplusplus
extern "C" {
#endif
// ---------------------------------------------------------------------
/*
* Normally we strip ALOGV (VERBOSE messages) from release builds.
* You can modify this (for example with "#define LOG_NDEBUG 0"
* at the top of your source file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
/*
* This is the local tag used for the following simplified
* logging macros. You can change this preprocessor definition
* before using the other macros to change the tag.
*/
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose log message using the current LOG_TAG.
*/
#ifndef ALOGV
#if LOG_NDEBUG
#define ALOGV(...) ((void)0)
#else
#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef ALOGV_IF
#if LOG_NDEBUG
#define ALOGV_IF(cond, ...) ((void)0)
#else
#define ALOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
/*
* Simplified macro to send a debug log message using the current LOG_TAG.
*/
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGD_IF
#define ALOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info log message using the current LOG_TAG.
*/
#ifndef ALOGI
#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGI_IF
#define ALOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning log message using the current LOG_TAG.
*/
#ifndef ALOGW
#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGW_IF
#define ALOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error log message using the current LOG_TAG.
*/
#ifndef ALOGE
#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGE_IF
#define ALOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
// ---------------------------------------------------------------------
/*
* Conditional based on whether the current LOG_TAG is enabled at
* verbose priority.
*/
#ifndef IF_ALOGV
#if LOG_NDEBUG
#define IF_ALOGV() if (false)
#else
#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
#endif
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* debug priority.
*/
#ifndef IF_ALOGD
#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* info priority.
*/
#ifndef IF_ALOGI
#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* warn priority.
*/
#ifndef IF_ALOGW
#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* error priority.
*/
#ifndef IF_ALOGE
#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose system log message using the current LOG_TAG.
*/
#ifndef SLOGV
#if LOG_NDEBUG
#define SLOGV(...) ((void)0)
#else
#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef SLOGV_IF
#if LOG_NDEBUG
#define SLOGV_IF(cond, ...) ((void)0)
#else
#define SLOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
/*
* Simplified macro to send a debug system log message using the current LOG_TAG.
*/
#ifndef SLOGD
#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGD_IF
#define SLOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info system log message using the current LOG_TAG.
*/
#ifndef SLOGI
#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGI_IF
#define SLOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning system log message using the current LOG_TAG.
*/
#ifndef SLOGW
#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGW_IF
#define SLOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error system log message using the current LOG_TAG.
*/
#ifndef SLOGE
#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef SLOGE_IF
#define SLOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose radio log message using the current LOG_TAG.
*/
#ifndef RLOGV
#if LOG_NDEBUG
#define RLOGV(...) ((void)0)
#else
#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef RLOGV_IF
#if LOG_NDEBUG
#define RLOGV_IF(cond, ...) ((void)0)
#else
#define RLOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
/*
* Simplified macro to send a debug radio log message using the current LOG_TAG.
*/
#ifndef RLOGD
#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGD_IF
#define RLOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info radio log message using the current LOG_TAG.
*/
#ifndef RLOGI
#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGI_IF
#define RLOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning radio log message using the current LOG_TAG.
*/
#ifndef RLOGW
#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGW_IF
#define RLOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error radio log message using the current LOG_TAG.
*/
#ifndef RLOGE
#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef RLOGE_IF
#define RLOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
// ---------------------------------------------------------------------
/*
* Log a fatal error. If the given condition fails, this stops program
* execution like a normal assertion, but also generating the given message.
* It is NOT stripped from release builds. Note that the condition test
* is -inverted- from the normal assert() semantics.
*/
#ifndef LOG_ALWAYS_FATAL_IF
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
: (void)0 )
#endif
#ifndef LOG_ALWAYS_FATAL
#define LOG_ALWAYS_FATAL(...) \
( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
#endif
/*
* Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
* are stripped out of release builds.
*/
#if LOG_NDEBUG
#ifndef LOG_FATAL_IF
#define LOG_FATAL_IF(cond, ...) ((void)0)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) ((void)0)
#endif
#else
#ifndef LOG_FATAL_IF
#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
#endif
#endif
/*
* Assertion that generates a log message when the assertion fails.
* Stripped out of release builds. Uses the current LOG_TAG.
*/
#ifndef ALOG_ASSERT
#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
#endif
// ---------------------------------------------------------------------
/*
* Basic log message macro.
*
* Example:
* ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
*
* The second argument may be NULL or "" to indicate the "global" tag.
*/
#ifndef ALOG
#define ALOG(priority, tag, ...) \
LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to specify a number for the priority.
*/
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
android_printLog(priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to pass in a varargs ("args" is a va_list).
*/
#ifndef LOG_PRI_VA
#define LOG_PRI_VA(priority, tag, fmt, args) \
android_vprintLog(priority, NULL, tag, fmt, args)
#endif
/*
* Conditional given a desired logging priority and tag.
*/
#ifndef IF_ALOG
#define IF_ALOG(priority, tag) \
if (android_testLog(ANDROID_##priority, tag))
#endif
// ---------------------------------------------------------------------
/*
* Event logging.
*/
/*
* Event log entry types. These must match up with the declarations in
* java/android/android/util/EventLog.java.
*/
typedef enum {
EVENT_TYPE_INT = 0,
EVENT_TYPE_LONG = 1,
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
} AndroidEventLogType;
#ifndef LOG_EVENT_INT
#define LOG_EVENT_INT(_tag, _value) { \
int intBuf = _value; \
(void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \
sizeof(intBuf)); \
}
#endif
#ifndef LOG_EVENT_LONG
#define LOG_EVENT_LONG(_tag, _value) { \
long long longBuf = _value; \
(void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \
sizeof(longBuf)); \
}
#endif
#ifndef LOG_EVENT_STRING
#define LOG_EVENT_STRING(_tag, _value) \
((void) 0) /* not implemented -- must combine len with string */
#endif
/* TODO: something for LIST */
/*
* ===========================================================================
*
* The stuff in the rest of this file should not be used directly.
*/
#define android_printLog(prio, tag, fmt...) \
__android_log_print(prio, tag, fmt)
#define android_vprintLog(prio, cond, tag, fmt...) \
__android_log_vprint(prio, tag, fmt)
/* XXX Macros to work around syntax errors in places where format string
* arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
* (happens only in debug builds).
*/
/* Returns 2nd arg. Used to substitute default value if caller's vararg list
* is empty.
*/
#define __android_second(dummy, second, ...) second
/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
* returns nothing.
*/
#define __android_rest(first, ...) , ## __VA_ARGS__
#define android_printAssert(cond, tag, fmt...) \
__android_log_assert(cond, tag, \
__android_second(0, ## fmt, NULL) __android_rest(fmt))
#define android_writeLog(prio, tag, text) \
__android_log_write(prio, tag, text)
#define android_bWriteLog(tag, payload, len) \
__android_log_bwrite(tag, payload, len)
#define android_btWriteLog(tag, type, payload, len) \
__android_log_btwrite(tag, type, payload, len)
// TODO: remove these prototypes and their users
#define android_testLog(prio, tag) (1)
#define android_writevLog(vec,num) do{}while(0)
#define android_write1Log(str,len) do{}while (0)
#define android_setMinPriority(tag, prio) do{}while(0)
//#define android_logToCallback(func) do{}while(0)
#define android_logToFile(tag, file) (0)
#define android_logToFd(tag, fd) (0)
typedef enum {
LOG_ID_MAIN = 0,
LOG_ID_RADIO = 1,
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_MAX
} log_id_t;
/*
* Send a simple string to the log.
*/
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif // _LIBS_CUTILS_LOG_H

View file

@ -31,7 +31,7 @@
#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif
#include <cutils/uio.h>
#include <log/uio.h>
#include <stdarg.h>
#ifdef __cplusplus

View file

@ -17,9 +17,9 @@
#ifndef _LOGPRINT_H
#define _LOGPRINT_H
#include <cutils/log.h>
#include <cutils/logger.h>
#include <cutils/event_tag_map.h>
#include <log/log.h>
#include <log/logger.h>
#include <log/event_tag_map.h>
#include <pthread.h>
#ifdef __cplusplus

147
include/memtrack/memtrack.h Normal file
View file

@ -0,0 +1,147 @@
/*
* Copyright (C) 2013 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 _LIBMEMTRACK_MEMTRACK_H_
#define _LIBMEMTRACK_MEMTRACK_H_
#include <sys/types.h>
#include <stddef.h>
#include <cutils/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* struct memtrack_proc
*
* an opaque handle to the memory stats on a process.
* Created with memtrack_proc_new, destroyed by
* memtrack_proc_destroy. Can be reused multiple times with
* memtrack_proc_get.
*/
struct memtrack_proc;
/**
* memtrack_init
*
* Must be called once before calling any other functions. After this function
* is called, everything else is thread-safe.
*
* Returns 0 on success, -errno on error.
*/
int memtrack_init(void);
/**
* memtrack_proc_new
*
* Return a new handle to hold process memory stats.
*
* Returns NULL on error.
*/
struct memtrack_proc *memtrack_proc_new(void);
/**
* memtrack_proc_destroy
*
* Free all memory associated with a process memory stats handle.
*/
void memtrack_proc_destroy(struct memtrack_proc *p);
/**
* memtrack_proc_get
*
* Fill a process memory stats handle with data about the given pid. Can be
* called on a handle that was just allocated with memtrack_proc_new,
* or on a handle that has been previously passed to memtrack_proc_get
* to replace the data with new data on the same or another process. It is
* expected that the second call on the same handle should not require
* allocating any new memory.
*
* Returns 0 on success, -errno on error.
*/
int memtrack_proc_get(struct memtrack_proc *p, pid_t pid);
/**
* memtrack_proc_graphics_total
*
* Return total amount of memory that has been allocated for use as window
* buffers. Does not differentiate between memory that has already been
* accounted for by reading /proc/pid/smaps and memory that has not been
* accounted for.
*
* Returns non-negative size in bytes on success, -errno on error.
*/
ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p);
/**
* memtrack_proc_graphics_pss
*
* Return total amount of memory that has been allocated for use as window
* buffers, but has not already been accounted for by reading /proc/pid/smaps.
* Memory that is shared across processes may already be divided by the
* number of processes that share it (preferred), or may be charged in full to
* every process that shares it, depending on the capabilities of the driver.
*
* Returns non-negative size in bytes on success, -errno on error.
*/
ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p);
/**
* memtrack_proc_gl_total
*
* Same as memtrack_proc_graphics_total, but counts GL memory (which
* should not overlap with graphics memory) instead of graphics memory.
*
* Returns non-negative size in bytes on success, -errno on error.
*/
ssize_t memtrack_proc_gl_total(struct memtrack_proc *p);
/**
* memtrack_proc_gl_pss
*
* Same as memtrack_proc_graphics_total, but counts GL memory (which
* should not overlap with graphics memory) instead of graphics memory.
*
* Returns non-negative size in bytes on success, -errno on error.
*/
ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
/**
* memtrack_proc_gl_total
*
* Same as memtrack_proc_graphics_total, but counts miscellaneous memory
* not tracked by gl or graphics calls above.
*
* Returns non-negative size in bytes on success, -errno on error.
*/
ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
/**
* memtrack_proc_gl_pss
*
* Same as memtrack_proc_graphics_total, but counts miscellaneous memory
* not tracked by gl or graphics calls above.
*
* Returns non-negative size in bytes on success, -errno on error.
*/
ssize_t memtrack_proc_other_pss(struct memtrack_proc *p);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -30,7 +30,9 @@ extern int dhcp_do_request(const char *ifname,
char *dns[],
char *server,
uint32_t *lease,
char *vendorInfo);
char *vendorInfo,
char *domain,
char *mtu);
extern int dhcp_do_request_renew(const char *ifname,
char *ipaddr,
char *gateway,
@ -38,7 +40,9 @@ extern int dhcp_do_request_renew(const char *ifname,
char *dns[],
char *server,
uint32_t *lease,
char *vendorInfo);
char *vendorInfo,
char *domain,
char *mtu);
extern int dhcp_stop(const char *ifname);
extern int dhcp_release_lease(const char *ifname);
extern char *dhcp_get_errmsg();

View file

@ -34,8 +34,8 @@
#endif
/* This is the master Users and Groups config for the platform.
** DO NOT EVER RENUMBER.
*/
* DO NOT EVER RENUMBER
*/
#define AID_ROOT 0 /* traditional unix root user */
@ -72,6 +72,10 @@
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@ -108,50 +112,61 @@ struct android_id_info {
};
static const struct android_id_info android_ids[] = {
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
{ "bluetooth", AID_BLUETOOTH, },
{ "graphics", AID_GRAPHICS, },
{ "input", AID_INPUT, },
{ "audio", AID_AUDIO, },
{ "camera", AID_CAMERA, },
{ "log", AID_LOG, },
{ "compass", AID_COMPASS, },
{ "mount", AID_MOUNT, },
{ "wifi", AID_WIFI, },
{ "dhcp", AID_DHCP, },
{ "adb", AID_ADB, },
{ "install", AID_INSTALL, },
{ "media", AID_MEDIA, },
{ "drm", AID_DRM, },
{ "mdnsr", AID_MDNSR, },
{ "nfc", AID_NFC, },
{ "drmrpc", AID_DRMRPC, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
{ "sdcard_r", AID_SDCARD_R, },
{ "sdcard_rw", AID_SDCARD_RW, },
{ "media_rw", AID_MEDIA_RW, },
{ "vpn", AID_VPN, },
{ "keystore", AID_KEYSTORE, },
{ "usb", AID_USB, },
{ "mtp", AID_MTP, },
{ "gps", AID_GPS, },
{ "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
{ "net_admin", AID_NET_ADMIN, },
{ "net_bw_stats", AID_NET_BW_STATS, },
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "loop_radio", AID_LOOP_RADIO, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
{ "clat", AID_CLAT, },
{ "mediadrm", AID_MEDIA_DRM, },
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
{ "bluetooth", AID_BLUETOOTH, },
{ "graphics", AID_GRAPHICS, },
{ "input", AID_INPUT, },
{ "audio", AID_AUDIO, },
{ "camera", AID_CAMERA, },
{ "log", AID_LOG, },
{ "compass", AID_COMPASS, },
{ "mount", AID_MOUNT, },
{ "wifi", AID_WIFI, },
{ "adb", AID_ADB, },
{ "install", AID_INSTALL, },
{ "media", AID_MEDIA, },
{ "dhcp", AID_DHCP, },
{ "sdcard_rw", AID_SDCARD_RW, },
{ "vpn", AID_VPN, },
{ "keystore", AID_KEYSTORE, },
{ "usb", AID_USB, },
{ "drm", AID_DRM, },
{ "mdnsr", AID_MDNSR, },
{ "gps", AID_GPS, },
// AID_UNUSED1
{ "media_rw", AID_MEDIA_RW, },
{ "mtp", AID_MTP, },
// AID_UNUSED2
{ "drmrpc", AID_DRMRPC, },
{ "nfc", AID_NFC, },
{ "sdcard_r", AID_SDCARD_R, },
{ "clat", AID_CLAT, },
{ "loop_radio", AID_LOOP_RADIO, },
{ "mediadrm", AID_MEDIA_DRM, },
{ "package_info", AID_PACKAGE_INFO, },
{ "sdcard_pics", AID_SDCARD_PICS, },
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
{ "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
{ "net_admin", AID_NET_ADMIN, },
{ "net_bw_stats", AID_NET_BW_STATS, },
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};
#define android_id_count \
@ -229,7 +244,7 @@ static const struct fs_path_config android_files[] = {
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/tcpdump" },
{ 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
/* the following file has enhanced capabilities and IS included in user builds. */
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },

View file

@ -31,6 +31,9 @@ __BEGIN_DECLS
* frameworks/base/include/media/AudioSystem.h
*/
/* device address used to refer to the standard remote submix */
#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
typedef int audio_io_handle_t;
/* Audio stream types */
@ -69,6 +72,11 @@ typedef enum {
/* play the mix captured by this audio source. */
AUDIO_SOURCE_CNT,
AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1,
AUDIO_SOURCE_HOTWORD = 1999, /* A low-priority, preemptible audio source for
for background software hotword detection.
Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
Used only internally to the framework. Not exposed
at the audio HAL. */
} audio_source_t;
/* special audio session values
@ -383,9 +391,51 @@ typedef enum {
// controls related to voice calls.
AUDIO_OUTPUT_FLAG_FAST = 0x4, // output supports "fast tracks",
// defined elsewhere
AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8 // use deep audio buffers
AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10, // offload playback of compressed
// streams to hardware codec
AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20 // use non-blocking write
} audio_output_flags_t;
/* The audio input flags are analogous to audio output flags.
* Currently they are used only when an AudioRecord is created,
* to indicate a preference to be connected to an input stream with
* attributes corresponding to the specified flags.
*/
typedef enum {
AUDIO_INPUT_FLAG_NONE = 0x0, // no attributes
AUDIO_INPUT_FLAG_FAST = 0x1, // prefer an input that supports "fast tracks"
} audio_input_flags_t;
/* Additional information about compressed streams offloaded to
* hardware playback
* The version and size fields must be initialized by the caller by using
* one of the constants defined here.
*/
typedef struct {
uint16_t version; // version of the info structure
uint16_t size; // total size of the structure including version and size
uint32_t sample_rate; // sample rate in Hz
audio_channel_mask_t channel_mask; // channel mask
audio_format_t format; // audio format
audio_stream_type_t stream_type; // stream type
uint32_t bit_rate; // bit rate in bits per second
int64_t duration_us; // duration in microseconds, -1 if unknown
bool has_video; // true if stream is tied to a video stream
bool is_streaming; // true if streaming, false if local playback
} audio_offload_info_t;
#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
((((maj) & 0xff) << 8) | ((min) & 0xff))
#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1
static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
size: sizeof(audio_offload_info_t),
};
static inline bool audio_is_output_device(audio_devices_t device)
{
if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
@ -439,24 +489,25 @@ static inline bool audio_is_usb_device(audio_devices_t device)
static inline bool audio_is_remote_submix_device(audio_devices_t device)
{
if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX))
if ((device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
|| (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
return true;
else
return false;
}
static inline bool audio_is_input_channel(uint32_t channel)
static inline bool audio_is_input_channel(audio_channel_mask_t channel)
{
if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
return true;
return channel != 0;
else
return false;
}
static inline bool audio_is_output_channel(uint32_t channel)
static inline bool audio_is_output_channel(audio_channel_mask_t channel)
{
if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
return true;
return channel != 0;
else
return false;
}

View file

@ -42,15 +42,40 @@ extern "C" {
*/
enum {
/*
* "linear" color pixel formats:
*
* The pixel formats below contain sRGB data but are otherwise treated
* as linear formats, i.e.: no special operation is performed when
* reading or writing into a buffer in one of these formats
*/
HAL_PIXEL_FORMAT_RGBA_8888 = 1,
HAL_PIXEL_FORMAT_RGBX_8888 = 2,
HAL_PIXEL_FORMAT_RGB_888 = 3,
HAL_PIXEL_FORMAT_RGB_565 = 4,
HAL_PIXEL_FORMAT_BGRA_8888 = 5,
HAL_PIXEL_FORMAT_RGBA_5551 = 6,
HAL_PIXEL_FORMAT_RGBA_4444 = 7,
/* 0x8 - 0xFF range unavailable */
/*
* sRGB color pixel formats:
*
* The red, green and blue components are stored in sRGB space, and converted
* to linear space when read, using the standard sRGB to linear equation:
*
* Clinear = Csrgb / 12.92 for Csrgb <= 0.04045
* = (Csrgb + 0.055 / 1.055)^2.4 for Csrgb > 0.04045
*
* When written the inverse transformation is performed:
*
* Csrgb = 12.92 * Clinear for Clinear <= 0.0031308
* = 1.055 * Clinear^(1/2.4) - 0.055 for Clinear > 0.0031308
*
*
* The alpha component, if present, is always stored in linear space and
* is left unmodified when read or written.
*
*/
HAL_PIXEL_FORMAT_sRGB_A_8888 = 0xC,
HAL_PIXEL_FORMAT_sRGB_X_8888 = 0xD,
/*
* 0x100 - 0x1FF
@ -268,6 +293,8 @@ enum {
HAL_TRANSFORM_ROT_180 = 0x03,
/* rotate source image 270 degrees clockwise */
HAL_TRANSFORM_ROT_270 = 0x07,
/* don't use. see system/window.h */
HAL_TRANSFORM_RESERVED = 0x08,
};
#ifdef __cplusplus

View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2013 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_THREAD_DEFS_H
#define ANDROID_THREAD_DEFS_H
#include "graphics.h"
#if defined(__cplusplus)
extern "C" {
#endif
enum {
/*
* ***********************************************
* ** Keep in sync with android.os.Process.java **
* ***********************************************
*
* This maps directly to the "nice" priorities we use in Android.
* A thread priority should be chosen inverse-proportionally to
* the amount of work the thread is expected to do. The more work
* a thread will do, the less favorable priority it should get so that
* it doesn't starve the system. Threads not behaving properly might
* be "punished" by the kernel.
* Use the levels below when appropriate. Intermediate values are
* acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
*/
ANDROID_PRIORITY_LOWEST = 19,
/* use for background tasks */
ANDROID_PRIORITY_BACKGROUND = 10,
/* most threads run at normal priority */
ANDROID_PRIORITY_NORMAL = 0,
/* threads currently running a UI that the user is interacting with */
ANDROID_PRIORITY_FOREGROUND = -2,
/* the main UI thread has a slightly more favorable priority */
ANDROID_PRIORITY_DISPLAY = -4,
/* ui service treads might want to run at a urgent display (uncommon) */
ANDROID_PRIORITY_URGENT_DISPLAY = HAL_PRIORITY_URGENT_DISPLAY,
/* all normal audio threads */
ANDROID_PRIORITY_AUDIO = -16,
/* service audio threads (uncommon) */
ANDROID_PRIORITY_URGENT_AUDIO = -19,
/* should never be used in practice. regular process might not
* be allowed to use this level */
ANDROID_PRIORITY_HIGHEST = -20,
ANDROID_PRIORITY_DEFAULT = ANDROID_PRIORITY_NORMAL,
ANDROID_PRIORITY_MORE_FAVORABLE = -1,
ANDROID_PRIORITY_LESS_FAVORABLE = +1,
};
#if defined(__cplusplus)
}
#endif
#endif /* ANDROID_THREAD_DEFS_H */

View file

@ -230,7 +230,13 @@ enum {
* Boolean that indicates whether the consumer is running more than
* one buffer behind the producer.
*/
NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9
NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
/*
* The consumer gralloc usage bits currently set by the consumer.
* The values are defined in hardware/libhardware/include/gralloc.h.
*/
NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10
};
/* Valid operations for the (*perform)() hook.
@ -290,12 +296,15 @@ enum {
NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
/* flip source image vertically */
NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
/* rotate source image 90 degrees clock-wise */
/* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
/* rotate source image 180 degrees */
NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
/* rotate source image 270 degrees clock-wise */
NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
/* transforms source by the inverse transform of the screen it is displayed onto. This
* transform is applied last */
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
};
/* parameter for NATIVE_WINDOW_SET_SCALING_MODE */

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2007 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 _LIBS_UTILS_ANDROID_THREADS_H
#define _LIBS_UTILS_ANDROID_THREADS_H
#include <stdint.h>
#include <sys/types.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
#endif
#include <utils/ThreadDefs.h>
// ---------------------------------------------------------------------------
// C API
#ifdef __cplusplus
extern "C" {
#endif
// Create and run a new thread.
extern int androidCreateThread(android_thread_func_t, void *);
// Create thread with lots of parameters
extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
void *userData,
const char* threadName,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId);
// Get some sort of unique identifier for the current thread.
extern android_thread_id_t androidGetThreadId();
// Low-level thread creation -- never creates threads that can
// interact with the Java VM.
extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
void *userData,
const char* threadName,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId);
// set the same of the running thread
extern void androidSetThreadName(const char* name);
// Used by the Java Runtime to control how threads are created, so that
// they can be proper and lovely Java threads.
typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
void *userData,
const char* threadName,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId);
extern void androidSetCreateThreadFunc(android_create_thread_fn func);
// ------------------------------------------------------------------
// Extra functions working with raw pids.
// Get pid for the current thread.
extern pid_t androidGetTid();
#ifdef HAVE_ANDROID_OS
// Change the priority AND scheduling group of a particular thread. The priority
// should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION
// if the priority set failed, else another value if just the group set failed;
// in either case errno is set. Thread ID zero means current thread.
extern int androidSetThreadPriority(pid_t tid, int prio);
// Get the current priority of a particular thread. Returns one of the
// ANDROID_PRIORITY constants or a negative result in case of error.
extern int androidGetThreadPriority(pid_t tid);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
// ----------------------------------------------------------------------------
// C++ API
#ifdef __cplusplus
namespace android {
// ----------------------------------------------------------------------------
// Create and run a new thread.
inline bool createThread(thread_func_t f, void *a) {
return androidCreateThread(f, a) ? true : false;
}
// Create thread with lots of parameters
inline bool createThreadEtc(thread_func_t entryFunction,
void *userData,
const char* threadName = "android:unnamed_thread",
int32_t threadPriority = PRIORITY_DEFAULT,
size_t threadStackSize = 0,
thread_id_t *threadId = 0)
{
return androidCreateThreadEtc(entryFunction, userData, threadName,
threadPriority, threadStackSize, threadId) ? true : false;
}
// Get some sort of unique identifier for the current thread.
inline thread_id_t getThreadId() {
return androidGetThreadId();
}
// ----------------------------------------------------------------------------
}; // namespace android
#endif // __cplusplus
// ----------------------------------------------------------------------------
#endif // _LIBS_UTILS_ANDROID_THREADS_H

22
include/utils/Atomic.h Normal file
View file

@ -0,0 +1,22 @@
/*
* Copyright (C) 2005 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_UTILS_ATOMIC_H
#define ANDROID_UTILS_ATOMIC_H
#include <cutils/atomic.h>
#endif // ANDROID_UTILS_ATOMIC_H

View file

@ -0,0 +1,402 @@
/*
* Copyright (C) 2011 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_BASIC_HASHTABLE_H
#define ANDROID_BASIC_HASHTABLE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/SharedBuffer.h>
#include <utils/TypeHelpers.h>
namespace android {
/* Implementation type. Nothing to see here. */
class BasicHashtableImpl {
protected:
struct Bucket {
// The collision flag indicates that the bucket is part of a collision chain
// such that at least two entries both hash to this bucket. When true, we
// may need to seek further along the chain to find the entry.
static const uint32_t COLLISION = 0x80000000UL;
// The present flag indicates that the bucket contains an initialized entry value.
static const uint32_t PRESENT = 0x40000000UL;
// Mask for 30 bits worth of the hash code that are stored within the bucket to
// speed up lookups and rehashing by eliminating the need to recalculate the
// hash code of the entry's key.
static const uint32_t HASH_MASK = 0x3fffffffUL;
// Combined value that stores the collision and present flags as well as
// a 30 bit hash code.
uint32_t cookie;
// Storage for the entry begins here.
char entry[0];
};
BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor,
size_t minimumInitialCapacity, float loadFactor);
BasicHashtableImpl(const BasicHashtableImpl& other);
virtual ~BasicHashtableImpl();
void dispose();
inline void edit() {
if (mBuckets && !SharedBuffer::bufferFromData(mBuckets)->onlyOwner()) {
clone();
}
}
void setTo(const BasicHashtableImpl& other);
void clear();
ssize_t next(ssize_t index) const;
ssize_t find(ssize_t index, hash_t hash, const void* __restrict__ key) const;
size_t add(hash_t hash, const void* __restrict__ entry);
void removeAt(size_t index);
void rehash(size_t minimumCapacity, float loadFactor);
const size_t mBucketSize; // number of bytes per bucket including the entry
const bool mHasTrivialDestructor; // true if the entry type does not require destruction
size_t mCapacity; // number of buckets that can be filled before exceeding load factor
float mLoadFactor; // load factor
size_t mSize; // number of elements actually in the table
size_t mFilledBuckets; // number of buckets for which collision or present is true
size_t mBucketCount; // number of slots in the mBuckets array
void* mBuckets; // array of buckets, as a SharedBuffer
inline const Bucket& bucketAt(const void* __restrict__ buckets, size_t index) const {
return *reinterpret_cast<const Bucket*>(
static_cast<const uint8_t*>(buckets) + index * mBucketSize);
}
inline Bucket& bucketAt(void* __restrict__ buckets, size_t index) const {
return *reinterpret_cast<Bucket*>(static_cast<uint8_t*>(buckets) + index * mBucketSize);
}
virtual bool compareBucketKey(const Bucket& bucket, const void* __restrict__ key) const = 0;
virtual void initializeBucketEntry(Bucket& bucket, const void* __restrict__ entry) const = 0;
virtual void destroyBucketEntry(Bucket& bucket) const = 0;
private:
void clone();
// Allocates a bucket array as a SharedBuffer.
void* allocateBuckets(size_t count) const;
// Releases a bucket array's associated SharedBuffer.
void releaseBuckets(void* __restrict__ buckets, size_t count) const;
// Destroys the contents of buckets (invokes destroyBucketEntry for each
// populated bucket if needed).
void destroyBuckets(void* __restrict__ buckets, size_t count) const;
// Copies the content of buckets (copies the cookie and invokes copyBucketEntry
// for each populated bucket if needed).
void copyBuckets(const void* __restrict__ fromBuckets,
void* __restrict__ toBuckets, size_t count) const;
// Determines the appropriate size of a bucket array to store a certain minimum
// number of entries and returns its effective capacity.
static void determineCapacity(size_t minimumCapacity, float loadFactor,
size_t* __restrict__ outBucketCount, size_t* __restrict__ outCapacity);
// Trim a hash code to 30 bits to match what we store in the bucket's cookie.
inline static hash_t trimHash(hash_t hash) {
return (hash & Bucket::HASH_MASK) ^ (hash >> 30);
}
// Returns the index of the first bucket that is in the collision chain
// for the specified hash code, given the total number of buckets.
// (Primary hash)
inline static size_t chainStart(hash_t hash, size_t count) {
return hash % count;
}
// Returns the increment to add to a bucket index to seek to the next bucket
// in the collision chain for the specified hash code, given the total number of buckets.
// (Secondary hash)
inline static size_t chainIncrement(hash_t hash, size_t count) {
return ((hash >> 7) | (hash << 25)) % (count - 1) + 1;
}
// Returns the index of the next bucket that is in the collision chain
// that is defined by the specified increment, given the total number of buckets.
inline static size_t chainSeek(size_t index, size_t increment, size_t count) {
return (index + increment) % count;
}
};
/*
* A BasicHashtable stores entries that are indexed by hash code in place
* within an array. The basic operations are finding entries by key,
* adding new entries and removing existing entries.
*
* This class provides a very limited set of operations with simple semantics.
* It is intended to be used as a building block to construct more complex
* and interesting data structures such as HashMap. Think very hard before
* adding anything extra to BasicHashtable, it probably belongs at a
* higher level of abstraction.
*
* TKey: The key type.
* TEntry: The entry type which is what is actually stored in the array.
*
* TKey must support the following contract:
* bool operator==(const TKey& other) const; // return true if equal
* bool operator!=(const TKey& other) const; // return true if unequal
*
* TEntry must support the following contract:
* const TKey& getKey() const; // get the key from the entry
*
* This class supports storing entries with duplicate keys. Of course, it can't
* tell them apart during removal so only the first entry will be removed.
* We do this because it means that operations like add() can't fail.
*/
template <typename TKey, typename TEntry>
class BasicHashtable : private BasicHashtableImpl {
public:
/* Creates a hashtable with the specified minimum initial capacity.
* The underlying array will be created when the first entry is added.
*
* minimumInitialCapacity: The minimum initial capacity for the hashtable.
* Default is 0.
* loadFactor: The desired load factor for the hashtable, between 0 and 1.
* Default is 0.75.
*/
BasicHashtable(size_t minimumInitialCapacity = 0, float loadFactor = 0.75f);
/* Copies a hashtable.
* The underlying storage is shared copy-on-write.
*/
BasicHashtable(const BasicHashtable& other);
/* Clears and destroys the hashtable.
*/
virtual ~BasicHashtable();
/* Making this hashtable a copy of the other hashtable.
* The underlying storage is shared copy-on-write.
*
* other: The hashtable to copy.
*/
inline BasicHashtable<TKey, TEntry>& operator =(const BasicHashtable<TKey, TEntry> & other) {
setTo(other);
return *this;
}
/* Returns the number of entries in the hashtable.
*/
inline size_t size() const {
return mSize;
}
/* Returns the capacity of the hashtable, which is the number of elements that can
* added to the hashtable without requiring it to be grown.
*/
inline size_t capacity() const {
return mCapacity;
}
/* Returns the number of buckets that the hashtable has, which is the size of its
* underlying array.
*/
inline size_t bucketCount() const {
return mBucketCount;
}
/* Returns the load factor of the hashtable. */
inline float loadFactor() const {
return mLoadFactor;
};
/* Returns a const reference to the entry at the specified index.
*
* index: The index of the entry to retrieve. Must be a valid index within
* the bounds of the hashtable.
*/
inline const TEntry& entryAt(size_t index) const {
return entryFor(bucketAt(mBuckets, index));
}
/* Returns a non-const reference to the entry at the specified index.
*
* index: The index of the entry to edit. Must be a valid index within
* the bounds of the hashtable.
*/
inline TEntry& editEntryAt(size_t index) {
edit();
return entryFor(bucketAt(mBuckets, index));
}
/* Clears the hashtable.
* All entries in the hashtable are destroyed immediately.
* If you need to do something special with the entries in the hashtable then iterate
* over them and do what you need before clearing the hashtable.
*/
inline void clear() {
BasicHashtableImpl::clear();
}
/* Returns the index of the next entry in the hashtable given the index of a previous entry.
* If the given index is -1, then returns the index of the first entry in the hashtable,
* if there is one, or -1 otherwise.
* If the given index is not -1, then returns the index of the next entry in the hashtable,
* in strictly increasing order, or -1 if there are none left.
*
* index: The index of the previous entry that was iterated, or -1 to begin
* iteration at the beginning of the hashtable.
*/
inline ssize_t next(ssize_t index) const {
return BasicHashtableImpl::next(index);
}
/* Finds the index of an entry with the specified key.
* If the given index is -1, then returns the index of the first matching entry,
* otherwise returns the index of the next matching entry.
* If the hashtable contains multiple entries with keys that match the requested
* key, then the sequence of entries returned is arbitrary.
* Returns -1 if no entry was found.
*
* index: The index of the previous entry with the specified key, or -1 to
* find the first matching entry.
* hash: The hashcode of the key.
* key: The key.
*/
inline ssize_t find(ssize_t index, hash_t hash, const TKey& key) const {
return BasicHashtableImpl::find(index, hash, &key);
}
/* Adds the entry to the hashtable.
* Returns the index of the newly added entry.
* If an entry with the same key already exists, then a duplicate entry is added.
* If the entry will not fit, then the hashtable's capacity is increased and
* its contents are rehashed. See rehash().
*
* hash: The hashcode of the key.
* entry: The entry to add.
*/
inline size_t add(hash_t hash, const TEntry& entry) {
return BasicHashtableImpl::add(hash, &entry);
}
/* Removes the entry with the specified index from the hashtable.
* The entry is destroyed immediately.
* The index must be valid.
*
* The hashtable is not compacted after an item is removed, so it is legal
* to continue iterating over the hashtable using next() or find().
*
* index: The index of the entry to remove. Must be a valid index within the
* bounds of the hashtable, and it must refer to an existing entry.
*/
inline void removeAt(size_t index) {
BasicHashtableImpl::removeAt(index);
}
/* Rehashes the contents of the hashtable.
* Grows the hashtable to at least the specified minimum capacity or the
* current number of elements, whichever is larger.
*
* Rehashing causes all entries to be copied and the entry indices may change.
* Although the hash codes are cached by the hashtable, rehashing can be an
* expensive operation and should be avoided unless the hashtable's size
* needs to be changed.
*
* Rehashing is the only way to change the capacity or load factor of the
* hashtable once it has been created. It can be used to compact the
* hashtable by choosing a minimum capacity that is smaller than the current
* capacity (such as 0).
*
* minimumCapacity: The desired minimum capacity after rehashing.
* loadFactor: The desired load factor after rehashing.
*/
inline void rehash(size_t minimumCapacity, float loadFactor) {
BasicHashtableImpl::rehash(minimumCapacity, loadFactor);
}
/* Determines whether there is room to add another entry without rehashing.
* When this returns true, a subsequent add() operation is guaranteed to
* complete without performing a rehash.
*/
inline bool hasMoreRoom() const {
return mCapacity > mFilledBuckets;
}
protected:
static inline const TEntry& entryFor(const Bucket& bucket) {
return reinterpret_cast<const TEntry&>(bucket.entry);
}
static inline TEntry& entryFor(Bucket& bucket) {
return reinterpret_cast<TEntry&>(bucket.entry);
}
virtual bool compareBucketKey(const Bucket& bucket, const void* __restrict__ key) const;
virtual void initializeBucketEntry(Bucket& bucket, const void* __restrict__ entry) const;
virtual void destroyBucketEntry(Bucket& bucket) const;
private:
// For dumping the raw contents of a hashtable during testing.
friend class BasicHashtableTest;
inline uint32_t cookieAt(size_t index) const {
return bucketAt(mBuckets, index).cookie;
}
};
template <typename TKey, typename TEntry>
BasicHashtable<TKey, TEntry>::BasicHashtable(size_t minimumInitialCapacity, float loadFactor) :
BasicHashtableImpl(sizeof(TEntry), traits<TEntry>::has_trivial_dtor,
minimumInitialCapacity, loadFactor) {
}
template <typename TKey, typename TEntry>
BasicHashtable<TKey, TEntry>::BasicHashtable(const BasicHashtable<TKey, TEntry>& other) :
BasicHashtableImpl(other) {
}
template <typename TKey, typename TEntry>
BasicHashtable<TKey, TEntry>::~BasicHashtable() {
dispose();
}
template <typename TKey, typename TEntry>
bool BasicHashtable<TKey, TEntry>::compareBucketKey(const Bucket& bucket,
const void* __restrict__ key) const {
return entryFor(bucket).getKey() == *static_cast<const TKey*>(key);
}
template <typename TKey, typename TEntry>
void BasicHashtable<TKey, TEntry>::initializeBucketEntry(Bucket& bucket,
const void* __restrict__ entry) const {
if (!traits<TEntry>::has_trivial_copy) {
new (&entryFor(bucket)) TEntry(*(static_cast<const TEntry*>(entry)));
} else {
memcpy(&entryFor(bucket), entry, sizeof(TEntry));
}
}
template <typename TKey, typename TEntry>
void BasicHashtable<TKey, TEntry>::destroyBucketEntry(Bucket& bucket) const {
if (!traits<TEntry>::has_trivial_dtor) {
entryFor(bucket).~TEntry();
}
}
}; // namespace android
#endif // ANDROID_BASIC_HASHTABLE_H

124
include/utils/BitSet.h Normal file
View file

@ -0,0 +1,124 @@
/*
* Copyright (C) 2010 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 UTILS_BITSET_H
#define UTILS_BITSET_H
#include <stdint.h>
#include <utils/TypeHelpers.h>
/*
* Contains some bit manipulation helpers.
*/
namespace android {
// A simple set of 32 bits that can be individually marked or cleared.
struct BitSet32 {
uint32_t value;
inline BitSet32() : value(0) { }
explicit inline BitSet32(uint32_t value) : value(value) { }
// Gets the value associated with a particular bit index.
static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; }
// Clears the bit set.
inline void clear() { value = 0; }
// Returns the number of marked bits in the set.
inline uint32_t count() const { return __builtin_popcount(value); }
// Returns true if the bit set does not contain any marked bits.
inline bool isEmpty() const { return ! value; }
// Returns true if the bit set does not contain any unmarked bits.
inline bool isFull() const { return value == 0xffffffff; }
// Returns true if the specified bit is marked.
inline bool hasBit(uint32_t n) const { return value & valueForBit(n); }
// Marks the specified bit.
inline void markBit(uint32_t n) { value |= valueForBit(n); }
// Clears the specified bit.
inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); }
// Finds the first marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t firstMarkedBit() const { return __builtin_clz(value); }
// Finds the first unmarked bit in the set.
// Result is undefined if all bits are marked.
inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
// Finds the last marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
// Finds the first marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearFirstMarkedBit() {
uint32_t n = firstMarkedBit();
clearBit(n);
return n;
}
// Finds the first unmarked bit in the set and marks it. Returns the bit index.
// Result is undefined if all bits are marked.
inline uint32_t markFirstUnmarkedBit() {
uint32_t n = firstUnmarkedBit();
markBit(n);
return n;
}
// Finds the last marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearLastMarkedBit() {
uint32_t n = lastMarkedBit();
clearBit(n);
return n;
}
// Gets the index of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t getIndexOfBit(uint32_t n) const {
return __builtin_popcount(value & ~(0xffffffffUL >> n));
}
inline bool operator== (const BitSet32& other) const { return value == other.value; }
inline bool operator!= (const BitSet32& other) const { return value != other.value; }
inline BitSet32 operator& (const BitSet32& other) const {
return BitSet32(value & other.value);
}
inline BitSet32& operator&= (const BitSet32& other) {
value &= other.value;
return *this;
}
inline BitSet32 operator| (const BitSet32& other) const {
return BitSet32(value | other.value);
}
inline BitSet32& operator|= (const BitSet32& other) {
value |= other.value;
return *this;
}
};
ANDROID_BASIC_TYPES_TRAITS(BitSet32)
} // namespace android
#endif // UTILS_BITSET_H

243
include/utils/BlobCache.h Normal file
View file

@ -0,0 +1,243 @@
/*
** Copyright 2011, 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_BLOB_CACHE_H
#define ANDROID_BLOB_CACHE_H
#include <stddef.h>
#include <utils/Flattenable.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/threads.h>
namespace android {
// A BlobCache is an in-memory cache for binary key/value pairs. A BlobCache
// does NOT provide any thread-safety guarantees.
//
// The cache contents can be serialized to an in-memory buffer or mmap'd file
// and then reloaded in a subsequent execution of the program. This
// serialization is non-portable and the data should only be used by the device
// that generated it.
class BlobCache : public RefBase {
public:
// Create an empty blob cache. The blob cache will cache key/value pairs
// with key and value sizes less than or equal to maxKeySize and
// maxValueSize, respectively. The total combined size of ALL cache entries
// (key sizes plus value sizes) will not exceed maxTotalSize.
BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
// set inserts a new binary value into the cache and associates it with the
// given binary key. If the key or value are too large for the cache then
// the cache remains unchanged. This includes the case where a different
// value was previously associated with the given key - the old value will
// remain in the cache. If the given key and value are small enough to be
// put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
// values specified to the BlobCache constructor), then the key/value pair
// will be in the cache after set returns. Note, however, that a subsequent
// call to set may evict old key/value pairs from the cache.
//
// Preconditions:
// key != NULL
// 0 < keySize
// value != NULL
// 0 < valueSize
void set(const void* key, size_t keySize, const void* value,
size_t valueSize);
// get retrieves from the cache the binary value associated with a given
// binary key. If the key is present in the cache then the length of the
// binary value associated with that key is returned. If the value argument
// is non-NULL and the size of the cached value is less than valueSize bytes
// then the cached value is copied into the buffer pointed to by the value
// argument. If the key is not present in the cache then 0 is returned and
// the buffer pointed to by the value argument is not modified.
//
// Note that when calling get multiple times with the same key, the later
// calls may fail, returning 0, even if earlier calls succeeded. The return
// value must be checked for each call.
//
// Preconditions:
// key != NULL
// 0 < keySize
// 0 <= valueSize
size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
// getFlattenedSize returns the number of bytes needed to store the entire
// serialized cache.
size_t getFlattenedSize() const;
// flatten serializes the current contents of the cache into the memory
// pointed to by 'buffer'. The serialized cache contents can later be
// loaded into a BlobCache object using the unflatten method. The contents
// of the BlobCache object will not be modified.
//
// Preconditions:
// size >= this.getFlattenedSize()
status_t flatten(void* buffer, size_t size) const;
// unflatten replaces the contents of the cache with the serialized cache
// contents in the memory pointed to by 'buffer'. The previous contents of
// the BlobCache will be evicted from the cache. If an error occurs while
// unflattening the serialized cache contents then the BlobCache will be
// left in an empty state.
//
status_t unflatten(void const* buffer, size_t size);
private:
// Copying is disallowed.
BlobCache(const BlobCache&);
void operator=(const BlobCache&);
// A random function helper to get around MinGW not having nrand48()
long int blob_random();
// clean evicts a randomly chosen set of entries from the cache such that
// the total size of all remaining entries is less than mMaxTotalSize/2.
void clean();
// isCleanable returns true if the cache is full enough for the clean method
// to have some effect, and false otherwise.
bool isCleanable() const;
// A Blob is an immutable sized unstructured data blob.
class Blob : public RefBase {
public:
Blob(const void* data, size_t size, bool copyData);
~Blob();
bool operator<(const Blob& rhs) const;
const void* getData() const;
size_t getSize() const;
private:
// Copying is not allowed.
Blob(const Blob&);
void operator=(const Blob&);
// mData points to the buffer containing the blob data.
const void* mData;
// mSize is the size of the blob data in bytes.
size_t mSize;
// mOwnsData indicates whether or not this Blob object should free the
// memory pointed to by mData when the Blob gets destructed.
bool mOwnsData;
};
// A CacheEntry is a single key/value pair in the cache.
class CacheEntry {
public:
CacheEntry();
CacheEntry(const sp<Blob>& key, const sp<Blob>& value);
CacheEntry(const CacheEntry& ce);
bool operator<(const CacheEntry& rhs) const;
const CacheEntry& operator=(const CacheEntry&);
sp<Blob> getKey() const;
sp<Blob> getValue() const;
void setValue(const sp<Blob>& value);
private:
// mKey is the key that identifies the cache entry.
sp<Blob> mKey;
// mValue is the cached data associated with the key.
sp<Blob> mValue;
};
// A Header is the header for the entire BlobCache serialization format. No
// need to make this portable, so we simply write the struct out.
struct Header {
// mMagicNumber is the magic number that identifies the data as
// serialized BlobCache contents. It must always contain 'Blb$'.
uint32_t mMagicNumber;
// mBlobCacheVersion is the serialization format version.
uint32_t mBlobCacheVersion;
// mDeviceVersion is the device-specific version of the cache. This can
// be used to invalidate the cache.
uint32_t mDeviceVersion;
// mNumEntries is number of cache entries following the header in the
// data.
size_t mNumEntries;
};
// An EntryHeader is the header for a serialized cache entry. No need to
// make this portable, so we simply write the struct out. Each EntryHeader
// is followed imediately by the key data and then the value data.
//
// The beginning of each serialized EntryHeader is 4-byte aligned, so the
// number of bytes that a serialized cache entry will occupy is:
//
// ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3
//
struct EntryHeader {
// mKeySize is the size of the entry key in bytes.
size_t mKeySize;
// mValueSize is the size of the entry value in bytes.
size_t mValueSize;
// mData contains both the key and value data for the cache entry. The
// key comes first followed immediately by the value.
uint8_t mData[];
};
// mMaxKeySize is the maximum key size that will be cached. Calls to
// BlobCache::set with a keySize parameter larger than mMaxKeySize will
// simply not add the key/value pair to the cache.
const size_t mMaxKeySize;
// mMaxValueSize is the maximum value size that will be cached. Calls to
// BlobCache::set with a valueSize parameter larger than mMaxValueSize will
// simply not add the key/value pair to the cache.
const size_t mMaxValueSize;
// mMaxTotalSize is the maximum size that all cache entries can occupy. This
// includes space for both keys and values. When a call to BlobCache::set
// would otherwise cause this limit to be exceeded, either the key/value
// pair passed to BlobCache::set will not be cached or other cache entries
// will be evicted from the cache to make room for the new entry.
const size_t mMaxTotalSize;
// mTotalSize is the total combined size of all keys and values currently in
// the cache.
size_t mTotalSize;
// mRandState is the pseudo-random number generator state. It is passed to
// nrand48 to generate random numbers when needed.
unsigned short mRandState[3];
// mCacheEntries stores all the cache entries that are resident in memory.
// Cache entries are added to it by the 'set' method.
SortedVector<CacheEntry> mCacheEntries;
};
}
#endif // ANDROID_BLOB_CACHE_H

81
include/utils/ByteOrder.h Normal file
View file

@ -0,0 +1,81 @@
/*
* 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.
*/
//
#ifndef _LIBS_UTILS_BYTE_ORDER_H
#define _LIBS_UTILS_BYTE_ORDER_H
#include <stdint.h>
#include <sys/types.h>
#ifdef HAVE_WINSOCK
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
/*
* These macros are like the hton/ntoh byte swapping macros,
* except they allow you to swap to and from the "device" byte
* order. The device byte order is the endianness of the target
* device -- for the ARM CPUs we use today, this is little endian.
*
* Note that the byte swapping functions have not been optimized
* much; performance is currently not an issue for them since the
* intent is to allow us to avoid byte swapping on the device.
*/
static inline uint32_t android_swap_long(uint32_t v)
{
return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
}
static inline uint16_t android_swap_short(uint16_t v)
{
return (v<<8) | (v>>8);
}
#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
#if BYTE_ORDER == DEVICE_BYTE_ORDER
#define dtohl(x) (x)
#define dtohs(x) (x)
#define htodl(x) (x)
#define htods(x) (x)
#else
#define dtohl(x) (android_swap_long(x))
#define dtohs(x) (android_swap_short(x))
#define htodl(x) (android_swap_long(x))
#define htods(x) (android_swap_short(x))
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#define fromlel(x) (x)
#define fromles(x) (x)
#define tolel(x) (x)
#define toles(x) (x)
#else
#define fromlel(x) (android_swap_long(x))
#define fromles(x) (android_swap_short(x))
#define tolel(x) (android_swap_long(x))
#define toles(x) (android_swap_short(x))
#endif
#endif // _LIBS_UTILS_BYTE_ORDER_H

76
include/utils/CallStack.h Normal file
View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2007 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_CALLSTACK_H
#define ANDROID_CALLSTACK_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/String8.h>
#include <corkscrew/backtrace.h>
// ---------------------------------------------------------------------------
namespace android {
class CallStack
{
public:
enum {
MAX_DEPTH = 31
};
CallStack();
CallStack(const char* logtag, int32_t ignoreDepth=1,
int32_t maxDepth=MAX_DEPTH);
CallStack(const CallStack& rhs);
~CallStack();
CallStack& operator = (const CallStack& rhs);
bool operator == (const CallStack& rhs) const;
bool operator != (const CallStack& rhs) const;
bool operator < (const CallStack& rhs) const;
bool operator >= (const CallStack& rhs) const;
bool operator > (const CallStack& rhs) const;
bool operator <= (const CallStack& rhs) const;
const void* operator [] (int index) const;
void clear();
void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH);
// Dump a stack trace to the log using the supplied logtag
void dump(const char* logtag, const char* prefix = 0) const;
// Return a string (possibly very long) containing the complete stack trace
String8 toString(const char* prefix = 0) const;
size_t size() const { return mCount; }
private:
size_t mCount;
backtrace_frame_t mStack[MAX_DEPTH];
};
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_CALLSTACK_H

65
include/utils/Compat.h Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2010 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 __LIB_UTILS_COMPAT_H
#define __LIB_UTILS_COMPAT_H
#include <unistd.h>
/* Compatibility definitions for non-Linux (i.e., BSD-based) hosts. */
#ifndef HAVE_OFF64_T
#if _FILE_OFFSET_BITS < 64
#error "_FILE_OFFSET_BITS < 64; large files are not supported on this platform"
#endif /* _FILE_OFFSET_BITS < 64 */
typedef off_t off64_t;
static inline off64_t lseek64(int fd, off64_t offset, int whence) {
return lseek(fd, offset, whence);
}
#ifdef HAVE_PREAD
static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) {
return pread(fd, buf, nbytes, offset);
}
#endif
#endif /* !HAVE_OFF64_T */
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
#else
# define ZD "%ld"
# define ZD_TYPE long
#endif
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
* <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
* not already defined, then define it here.
*/
#ifndef TEMP_FAILURE_RETRY
/* Used to retry syscalls that can return EINTR. */
#define TEMP_FAILURE_RETRY(exp) ({ \
typeof (exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; })
#endif
#endif /* __LIB_UTILS_COMPAT_H */

147
include/utils/Condition.h Normal file
View file

@ -0,0 +1,147 @@
/*
* Copyright (C) 2007 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 _LIBS_UTILS_CONDITION_H
#define _LIBS_UTILS_CONDITION_H
#include <stdint.h>
#include <sys/types.h>
#include <time.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
#endif
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/Timers.h>
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
/*
* Condition variable class. The implementation is system-dependent.
*
* Condition variables are paired up with mutexes. Lock the mutex,
* call wait(), then either re-wait() if things aren't quite what you want,
* or unlock the mutex and continue. All threads calling wait() must
* use the same mutex for a given Condition.
*/
class Condition {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
enum WakeUpType {
WAKE_UP_ONE = 0,
WAKE_UP_ALL = 1
};
Condition();
Condition(int type);
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
void signal();
// Signal the condition variable, allowing one or all threads to continue.
void signal(WakeUpType type) {
if (type == WAKE_UP_ONE) {
signal();
} else {
broadcast();
}
}
// Signal the condition variable, allowing all threads to continue.
void broadcast();
private:
#if defined(HAVE_PTHREADS)
pthread_cond_t mCond;
#else
void* mState;
#endif
};
// ---------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
inline Condition::Condition() {
pthread_cond_init(&mCond, NULL);
}
inline Condition::Condition(int type) {
if (type == SHARED) {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&mCond, &attr);
pthread_condattr_destroy(&attr);
} else {
pthread_cond_init(&mCond, NULL);
}
}
inline Condition::~Condition() {
pthread_cond_destroy(&mCond);
}
inline status_t Condition::wait(Mutex& mutex) {
return -pthread_cond_wait(&mCond, &mutex.mMutex);
}
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
struct timespec ts;
ts.tv_sec = reltime/1000000000;
ts.tv_nsec = reltime%1000000000;
return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
struct timespec ts;
#if defined(HAVE_POSIX_CLOCKS)
clock_gettime(CLOCK_REALTIME, &ts);
#else // HAVE_POSIX_CLOCKS
// we don't support the clocks here.
struct timeval t;
gettimeofday(&t, NULL);
ts.tv_sec = t.tv_sec;
ts.tv_nsec= t.tv_usec*1000;
#endif // HAVE_POSIX_CLOCKS
ts.tv_sec += reltime/1000000000;
ts.tv_nsec+= reltime%1000000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
ts.tv_sec += 1;
}
return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
}
inline void Condition::signal() {
pthread_cond_signal(&mCond);
}
inline void Condition::broadcast() {
pthread_cond_broadcast(&mCond);
}
#endif // HAVE_PTHREADS
// ---------------------------------------------------------------------------
}; // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_CONDITON_H

48
include/utils/Debug.h Normal file
View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005 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_UTILS_DEBUG_H
#define ANDROID_UTILS_DEBUG_H
#include <stdint.h>
#include <sys/types.h>
namespace android {
// ---------------------------------------------------------------------------
#ifdef __cplusplus
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
#define COMPILE_TIME_ASSERT(_exp) \
template class CompileTimeAssert< (_exp) >;
#endif
#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
CompileTimeAssert<( _exp )>();
// ---------------------------------------------------------------------------
#ifdef __cplusplus
template<bool C, typename LSH, typename RHS> struct CompileTimeIfElse;
template<typename LHS, typename RHS>
struct CompileTimeIfElse<true, LHS, RHS> { typedef LHS TYPE; };
template<typename LHS, typename RHS>
struct CompileTimeIfElse<false, LHS, RHS> { typedef RHS TYPE; };
#endif
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_UTILS_DEBUG_H

40
include/utils/Endian.h Normal file
View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 2005 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.
*/
//
// Android endian-ness defines.
//
#ifndef _LIBS_UTILS_ENDIAN_H
#define _LIBS_UTILS_ENDIAN_H
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
#else /*not HAVE_ENDIAN_H*/
#define __BIG_ENDIAN 0x1000
#define __LITTLE_ENDIAN 0x0001
#if defined(HAVE_LITTLE_ENDIAN)
# define __BYTE_ORDER __LITTLE_ENDIAN
#else
# define __BYTE_ORDER __BIG_ENDIAN
#endif
#endif /*not HAVE_ENDIAN_H*/
#endif /*_LIBS_UTILS_ENDIAN_H*/

88
include/utils/Errors.h Normal file
View file

@ -0,0 +1,88 @@
/*
* Copyright (C) 2007 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_ERRORS_H
#define ANDROID_ERRORS_H
#include <sys/types.h>
#include <errno.h>
namespace android {
// use this type to return error codes
#ifdef HAVE_MS_C_RUNTIME
typedef int status_t;
#else
typedef int32_t status_t;
#endif
/* the MS C runtime lacks a few error codes */
/*
* Error codes.
* All error codes are negative values.
*/
// Win32 #defines NO_ERROR as well. It has the same value, so there's no
// real conflict, though it's a bit awkward.
#ifdef _WIN32
# undef NO_ERROR
#endif
enum {
OK = 0, // Everything's swell.
NO_ERROR = 0, // No errors.
UNKNOWN_ERROR = 0x80000000,
NO_MEMORY = -ENOMEM,
INVALID_OPERATION = -ENOSYS,
BAD_VALUE = -EINVAL,
BAD_TYPE = 0x80000001,
NAME_NOT_FOUND = -ENOENT,
PERMISSION_DENIED = -EPERM,
NO_INIT = -ENODEV,
ALREADY_EXISTS = -EEXIST,
DEAD_OBJECT = -EPIPE,
FAILED_TRANSACTION = 0x80000002,
JPARKS_BROKE_IT = -EPIPE,
#if !defined(HAVE_MS_C_RUNTIME)
BAD_INDEX = -EOVERFLOW,
NOT_ENOUGH_DATA = -ENODATA,
WOULD_BLOCK = -EWOULDBLOCK,
TIMED_OUT = -ETIMEDOUT,
UNKNOWN_TRANSACTION = -EBADMSG,
#else
BAD_INDEX = -E2BIG,
NOT_ENOUGH_DATA = 0x80000003,
WOULD_BLOCK = 0x80000004,
TIMED_OUT = 0x80000005,
UNKNOWN_TRANSACTION = 0x80000006,
#endif
FDS_NOT_ALLOWED = 0x80000007,
};
// Restore define; enumeration is in "android" namespace, so the value defined
// there won't work for Win32 code in a different namespace.
#ifdef _WIN32
# define NO_ERROR 0L
#endif
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_ERRORS_H

136
include/utils/FileMap.h Normal file
View file

@ -0,0 +1,136 @@
/*
* 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.
*/
//
// Encapsulate a shared file mapping.
//
#ifndef __LIBS_FILE_MAP_H
#define __LIBS_FILE_MAP_H
#include <sys/types.h>
#include <utils/Compat.h>
#ifdef HAVE_WIN32_FILEMAP
#include <windows.h>
#endif
namespace android {
/*
* This represents a memory-mapped file. It might be the entire file or
* only part of it. This requires a little bookkeeping because the mapping
* needs to be aligned on page boundaries, and in some cases we'd like to
* have multiple references to the mapped area without creating additional
* maps.
*
* This always uses MAP_SHARED.
*
* TODO: we should be able to create a new FileMap that is a subset of
* an existing FileMap and shares the underlying mapped pages. Requires
* completing the refcounting stuff and possibly introducing the notion
* of a FileMap hierarchy.
*/
class FileMap {
public:
FileMap(void);
/*
* Create a new mapping on an open file.
*
* Closing the file descriptor does not unmap the pages, so we don't
* claim ownership of the fd.
*
* Returns "false" on failure.
*/
bool create(const char* origFileName, int fd,
off64_t offset, size_t length, bool readOnly);
/*
* Return the name of the file this map came from, if known.
*/
const char* getFileName(void) const { return mFileName; }
/*
* Get a pointer to the piece of the file we requested.
*/
void* getDataPtr(void) const { return mDataPtr; }
/*
* Get the length we requested.
*/
size_t getDataLength(void) const { return mDataLength; }
/*
* Get the data offset used to create this map.
*/
off64_t getDataOffset(void) const { return mDataOffset; }
/*
* Get a "copy" of the object.
*/
FileMap* acquire(void) { mRefCount++; return this; }
/*
* Call this when mapping is no longer needed.
*/
void release(void) {
if (--mRefCount <= 0)
delete this;
}
/*
* This maps directly to madvise() values, but allows us to avoid
* including <sys/mman.h> everywhere.
*/
enum MapAdvice {
NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED
};
/*
* Apply an madvise() call to the entire file.
*
* Returns 0 on success, -1 on failure.
*/
int advise(MapAdvice advice);
protected:
// don't delete objects; call release()
~FileMap(void);
private:
// these are not implemented
FileMap(const FileMap& src);
const FileMap& operator=(const FileMap& src);
int mRefCount; // reference count
char* mFileName; // original file name, if known
void* mBasePtr; // base of mmap area; page aligned
size_t mBaseLength; // length, measured from "mBasePtr"
off64_t mDataOffset; // offset used when map was created
void* mDataPtr; // start of requested data, offset from base
size_t mDataLength; // length, measured from "mDataPtr"
#ifdef HAVE_WIN32_FILEMAP
HANDLE mFileHandle; // Win32 file handle
HANDLE mFileMapping; // Win32 file mapping handle
#endif
static long mPageSize;
};
}; // namespace android
#endif // __LIBS_FILE_MAP_H

198
include/utils/Flattenable.h Normal file
View file

@ -0,0 +1,198 @@
/*
* Copyright (C) 2010 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_UTILS_FLATTENABLE_H
#define ANDROID_UTILS_FLATTENABLE_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Debug.h>
namespace android {
class FlattenableUtils {
public:
template<int N>
static size_t align(size_t size) {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
return (size + (N-1)) & ~(N-1);
}
template<int N>
static size_t align(void const*& buffer) {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
intptr_t b = intptr_t(buffer);
buffer = (void*)((intptr_t(buffer) + (N-1)) & ~(N-1));
return size_t(intptr_t(buffer) - b);
}
template<int N>
static size_t align(void*& buffer) {
return align<N>( const_cast<void const*&>(buffer) );
}
static void advance(void*& buffer, size_t& size, size_t offset) {
buffer = reinterpret_cast<void*>( intptr_t(buffer) + offset );
size -= offset;
}
static void advance(void const*& buffer, size_t& size, size_t offset) {
buffer = reinterpret_cast<void const*>( intptr_t(buffer) + offset );
size -= offset;
}
// write a POD structure
template<typename T>
static void write(void*& buffer, size_t& size, const T& value) {
*static_cast<T*>(buffer) = value;
advance(buffer, size, sizeof(T));
}
// read a POD structure
template<typename T>
static void read(void const*& buffer, size_t& size, T& value) {
value = *static_cast<T const*>(buffer);
advance(buffer, size, sizeof(T));
}
};
/*
* The Flattenable protocol allows an object to serialize itself out
* to a byte-buffer and an array of file descriptors.
* Flattenable objects must implement this protocol.
*/
template <typename T>
class Flattenable {
public:
// size in bytes of the flattened object
inline size_t getFlattenedSize() const;
// number of file descriptors to flatten
inline size_t getFdCount() const;
// flattens the object into buffer.
// size should be at least of getFlattenedSize()
// file descriptors are written in the fds[] array but ownership is
// not transfered (ie: they must be dupped by the caller of
// flatten() if needed).
inline status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
// unflattens the object from buffer.
// size should be equal to the value of getFlattenedSize() when the
// object was flattened.
// unflattened file descriptors are found in the fds[] array and
// don't need to be dupped(). ie: the caller of unflatten doesn't
// keep ownership. If a fd is not retained by unflatten() it must be
// explicitly closed.
inline status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
};
template<typename T>
inline size_t Flattenable<T>::getFlattenedSize() const {
return static_cast<T const*>(this)->T::getFlattenedSize();
}
template<typename T>
inline size_t Flattenable<T>::getFdCount() const {
return static_cast<T const*>(this)->T::getFdCount();
}
template<typename T>
inline status_t Flattenable<T>::flatten(
void*& buffer, size_t& size, int*& fds, size_t& count) const {
return static_cast<T const*>(this)->T::flatten(buffer, size, fds, count);
}
template<typename T>
inline status_t Flattenable<T>::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
return static_cast<T*>(this)->T::unflatten(buffer, size, fds, count);
}
/*
* LightFlattenable is a protocol allowing object to serialize themselves out
* to a byte-buffer. Because it doesn't handle file-descriptors,
* LightFlattenable is usually more size efficient than Flattenable.
* LightFlattenable objects must implement this protocol.
*/
template <typename T>
class LightFlattenable {
public:
// returns whether this object always flatten into the same size.
// for efficiency, this should always be inline.
inline bool isFixedSize() const;
// returns size in bytes of the flattened object. must be a constant.
inline size_t getFlattenedSize() const;
// flattens the object into buffer.
inline status_t flatten(void* buffer, size_t size) const;
// unflattens the object from buffer of given size.
inline status_t unflatten(void const* buffer, size_t size);
};
template <typename T>
inline bool LightFlattenable<T>::isFixedSize() const {
return static_cast<T const*>(this)->T::isFixedSize();
}
template <typename T>
inline size_t LightFlattenable<T>::getFlattenedSize() const {
return static_cast<T const*>(this)->T::getFlattenedSize();
}
template <typename T>
inline status_t LightFlattenable<T>::flatten(void* buffer, size_t size) const {
return static_cast<T const*>(this)->T::flatten(buffer, size);
}
template <typename T>
inline status_t LightFlattenable<T>::unflatten(void const* buffer, size_t size) {
return static_cast<T*>(this)->T::unflatten(buffer, size);
}
/*
* LightFlattenablePod is an implementation of the LightFlattenable protocol
* for POD (plain-old-data) objects.
* Simply derive from LightFlattenablePod<Foo> to make Foo flattenable; no
* need to implement any methods; obviously Foo must be a POD structure.
*/
template <typename T>
class LightFlattenablePod : public LightFlattenable<T> {
public:
inline bool isFixedSize() const {
return true;
}
inline size_t getFlattenedSize() const {
return sizeof(T);
}
inline status_t flatten(void* buffer, size_t size) const {
if (size < sizeof(T)) return NO_MEMORY;
*reinterpret_cast<T*>(buffer) = *static_cast<T const*>(this);
return NO_ERROR;
}
inline status_t unflatten(void const* buffer, size_t) {
*static_cast<T*>(this) = *reinterpret_cast<T const*>(buffer);
return NO_ERROR;
}
};
}; // namespace android
#endif /* ANDROID_UTILS_FLATTENABLE_H */

33
include/utils/Functor.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2011 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_FUNCTOR_H
#define ANDROID_FUNCTOR_H
#include <utils/Errors.h>
namespace android {
class Functor {
public:
Functor() {}
virtual ~Functor() {}
virtual status_t operator ()(int what, void* data) { return NO_ERROR; }
};
}; // namespace android
#endif // ANDROID_FUNCTOR_H

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Implementation of Jenkins one-at-a-time hash function. These choices are
* optimized for code size and portability, rather than raw speed. But speed
* should still be quite good.
**/
#ifndef ANDROID_JENKINS_HASH_H
#define ANDROID_JENKINS_HASH_H
#include <utils/TypeHelpers.h>
namespace android {
/* The Jenkins hash of a sequence of 32 bit words A, B, C is:
* Whiten(Mix(Mix(Mix(0, A), B), C)) */
inline uint32_t JenkinsHashMix(uint32_t hash, uint32_t data) {
hash += data;
hash += (hash << 10);
hash ^= (hash >> 6);
return hash;
}
hash_t JenkinsHashWhiten(uint32_t hash);
/* Helpful utility functions for hashing data in 32 bit chunks */
uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size);
uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size);
}
#endif // ANDROID_JENKINS_HASH_H

224
include/utils/KeyedVector.h Normal file
View file

@ -0,0 +1,224 @@
/*
* Copyright (C) 2005 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_KEYED_VECTOR_H
#define ANDROID_KEYED_VECTOR_H
#include <assert.h>
#include <stdint.h>
#include <sys/types.h>
#include <cutils/log.h>
#include <utils/SortedVector.h>
#include <utils/TypeHelpers.h>
#include <utils/Errors.h>
// ---------------------------------------------------------------------------
namespace android {
template <typename KEY, typename VALUE>
class KeyedVector
{
public:
typedef KEY key_type;
typedef VALUE value_type;
inline KeyedVector();
/*
* empty the vector
*/
inline void clear() { mVector.clear(); }
/*!
* vector stats
*/
//! returns number of items in the vector
inline size_t size() const { return mVector.size(); }
//! returns whether or not the vector is empty
inline bool isEmpty() const { return mVector.isEmpty(); }
//! returns how many items can be stored without reallocating the backing store
inline size_t capacity() const { return mVector.capacity(); }
//! sets the capacity. capacity can never be reduced less than size()
inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); }
// returns true if the arguments is known to be identical to this vector
inline bool isIdenticalTo(const KeyedVector& rhs) const;
/*!
* accessors
*/
const VALUE& valueFor(const KEY& key) const;
const VALUE& valueAt(size_t index) const;
const KEY& keyAt(size_t index) const;
ssize_t indexOfKey(const KEY& key) const;
const VALUE& operator[] (size_t index) const;
/*!
* modifying the array
*/
VALUE& editValueFor(const KEY& key);
VALUE& editValueAt(size_t index);
/*!
* add/insert/replace items
*/
ssize_t add(const KEY& key, const VALUE& item);
ssize_t replaceValueFor(const KEY& key, const VALUE& item);
ssize_t replaceValueAt(size_t index, const VALUE& item);
/*!
* remove items
*/
ssize_t removeItem(const KEY& key);
ssize_t removeItemsAt(size_t index, size_t count = 1);
private:
SortedVector< key_value_pair_t<KEY, VALUE> > mVector;
};
// KeyedVector<KEY, VALUE> can be trivially moved using memcpy() because its
// underlying SortedVector can be trivially moved.
template<typename KEY, typename VALUE> struct trait_trivial_move<KeyedVector<KEY, VALUE> > {
enum { value = trait_trivial_move<SortedVector< key_value_pair_t<KEY, VALUE> > >::value };
};
// ---------------------------------------------------------------------------
/**
* Variation of KeyedVector that holds a default value to return when
* valueFor() is called with a key that doesn't exist.
*/
template <typename KEY, typename VALUE>
class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
{
public:
inline DefaultKeyedVector(const VALUE& defValue = VALUE());
const VALUE& valueFor(const KEY& key) const;
private:
VALUE mDefault;
};
// ---------------------------------------------------------------------------
template<typename KEY, typename VALUE> inline
KeyedVector<KEY,VALUE>::KeyedVector()
{
}
template<typename KEY, typename VALUE> inline
bool KeyedVector<KEY,VALUE>::isIdenticalTo(const KeyedVector<KEY,VALUE>& rhs) const {
return mVector.array() == rhs.mVector.array();
}
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
}
template<typename KEY, typename VALUE> inline
const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
ssize_t i = this->indexOfKey(key);
LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
return mVector.itemAt(i).value;
}
template<typename KEY, typename VALUE> inline
const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const {
return mVector.itemAt(index).value;
}
template<typename KEY, typename VALUE> inline
const VALUE& KeyedVector<KEY,VALUE>::operator[] (size_t index) const {
return valueAt(index);
}
template<typename KEY, typename VALUE> inline
const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
return mVector.itemAt(index).key;
}
template<typename KEY, typename VALUE> inline
VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
ssize_t i = this->indexOfKey(key);
LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
return mVector.editItemAt(i).value;
}
template<typename KEY, typename VALUE> inline
VALUE& KeyedVector<KEY,VALUE>::editValueAt(size_t index) {
return mVector.editItemAt(index).value;
}
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::add(const KEY& key, const VALUE& value) {
return mVector.add( key_value_pair_t<KEY,VALUE>(key, value) );
}
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& value) {
key_value_pair_t<KEY,VALUE> pair(key, value);
mVector.remove(pair);
return mVector.add(pair);
}
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
if (index<size()) {
mVector.editItemAt(index).value = item;
return index;
}
return BAD_INDEX;
}
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::removeItem(const KEY& key) {
return mVector.remove(key_value_pair_t<KEY,VALUE>(key));
}
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY, VALUE>::removeItemsAt(size_t index, size_t count) {
return mVector.removeItemsAt(index, count);
}
// ---------------------------------------------------------------------------
template<typename KEY, typename VALUE> inline
DefaultKeyedVector<KEY,VALUE>::DefaultKeyedVector(const VALUE& defValue)
: mDefault(defValue)
{
}
template<typename KEY, typename VALUE> inline
const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
ssize_t i = this->indexOfKey(key);
return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
}
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_KEYED_VECTOR_H

View file

@ -0,0 +1,97 @@
/*
* Copyright 2012, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ANDROID_LINEARALLOCATOR_H
#define ANDROID_LINEARALLOCATOR_H
#include <stddef.h>
namespace android {
/**
* A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
* the overhead of malloc when many objects are allocated. It is most useful when creating many
* small objects with a similar lifetime, and doesn't add significant overhead for large
* allocations.
*/
class LinearAllocator {
public:
LinearAllocator();
~LinearAllocator();
/**
* Reserves and returns a region of memory of at least size 'size', aligning as needed.
* Typically this is used in an object's overridden new() method or as a replacement for malloc.
*
* The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
* delete() on an object stored in a buffer is needed, it should be overridden to use
* rewindIfLastAlloc()
*/
void* alloc(size_t size);
/**
* Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
* state if possible. No destructors are called.
*/
void rewindIfLastAlloc(void* ptr, size_t allocSize);
/**
* Dump memory usage statistics to the log (allocated and wasted space)
*/
void dumpMemoryStats(const char* prefix = "");
/**
* The number of bytes used for buffers allocated in the LinearAllocator (does not count space
* wasted)
*/
size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
private:
LinearAllocator(const LinearAllocator& other);
class Page;
Page* newPage(size_t pageSize);
bool fitsInCurrentPage(size_t size);
void ensureNext(size_t size);
void* start(Page *p);
void* end(Page* p);
size_t mPageSize;
size_t mMaxAllocSize;
void* mNext;
Page* mCurrentPage;
Page* mPages;
// Memory usage tracking
size_t mTotalAllocated;
size_t mWastedSpace;
size_t mPageCount;
size_t mDedicatedPageCount;
};
}; // namespace android
#endif // ANDROID_LINEARALLOCATOR_H

View file

@ -0,0 +1,64 @@
/*
* Copyright (C) 2011 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 _LIBS_UTILS_LINEAR_TRANSFORM_H
#define _LIBS_UTILS_LINEAR_TRANSFORM_H
#include <stdint.h>
namespace android {
// LinearTransform defines a structure which hold the definition of a
// transformation from single dimensional coordinate system A into coordinate
// system B (and back again). Values in A and in B are 64 bit, the linear
// scale factor is expressed as a rational number using two 32 bit values.
//
// Specifically, let
// f(a) = b
// F(b) = f^-1(b) = a
// then
//
// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
//
// and
//
// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
//
struct LinearTransform {
int64_t a_zero;
int64_t b_zero;
int32_t a_to_b_numer;
uint32_t a_to_b_denom;
// Transform from A->B
// Returns true on success, or false in the case of a singularity or an
// overflow.
bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
// Transform from B->A
// Returns true on success, or false in the case of a singularity or an
// overflow.
bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
// Helpers which will reduce the fraction N/D using Euclid's method.
template <class T> static void reduce(T* N, T* D);
static void reduce(int32_t* N, uint32_t* D);
};
}
#endif // _LIBS_UTILS_LINEAR_TRANSFORM_H

332
include/utils/List.h Normal file
View file

@ -0,0 +1,332 @@
/*
* Copyright (C) 2005 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.
*/
//
// Templated list class. Normally we'd use STL, but we don't have that.
// This class mimics STL's interfaces.
//
// Objects are copied into the list with the '=' operator or with copy-
// construction, so if the compiler's auto-generated versions won't work for
// you, define your own.
//
// The only class you want to use from here is "List".
//
#ifndef _LIBS_UTILS_LIST_H
#define _LIBS_UTILS_LIST_H
#include <stddef.h>
#include <stdint.h>
namespace android {
/*
* Doubly-linked list. Instantiate with "List<MyClass> myList".
*
* Objects added to the list are copied using the assignment operator,
* so this must be defined.
*/
template<typename T>
class List
{
protected:
/*
* One element in the list.
*/
class _Node {
public:
explicit _Node(const T& val) : mVal(val) {}
~_Node() {}
inline T& getRef() { return mVal; }
inline const T& getRef() const { return mVal; }
inline _Node* getPrev() const { return mpPrev; }
inline _Node* getNext() const { return mpNext; }
inline void setVal(const T& val) { mVal = val; }
inline void setPrev(_Node* ptr) { mpPrev = ptr; }
inline void setNext(_Node* ptr) { mpNext = ptr; }
private:
friend class List;
friend class _ListIterator;
T mVal;
_Node* mpPrev;
_Node* mpNext;
};
/*
* Iterator for walking through the list.
*/
template <typename TYPE>
struct CONST_ITERATOR {
typedef _Node const * NodePtr;
typedef const TYPE Type;
};
template <typename TYPE>
struct NON_CONST_ITERATOR {
typedef _Node* NodePtr;
typedef TYPE Type;
};
template<
typename U,
template <class> class Constness
>
class _ListIterator {
typedef _ListIterator<U, Constness> _Iter;
typedef typename Constness<U>::NodePtr _NodePtr;
typedef typename Constness<U>::Type _Type;
explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
public:
_ListIterator() {}
_ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
~_ListIterator() {}
// this will handle conversions from iterator to const_iterator
// (and also all convertible iterators)
// Here, in this implementation, the iterators can be converted
// if the nodes can be converted
template<typename V> explicit
_ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
/*
* Dereference operator. Used to get at the juicy insides.
*/
_Type& operator*() const { return mpNode->getRef(); }
_Type* operator->() const { return &(mpNode->getRef()); }
/*
* Iterator comparison.
*/
inline bool operator==(const _Iter& right) const {
return mpNode == right.mpNode; }
inline bool operator!=(const _Iter& right) const {
return mpNode != right.mpNode; }
/*
* handle comparisons between iterator and const_iterator
*/
template<typename OTHER>
inline bool operator==(const OTHER& right) const {
return mpNode == right.mpNode; }
template<typename OTHER>
inline bool operator!=(const OTHER& right) const {
return mpNode != right.mpNode; }
/*
* Incr/decr, used to move through the list.
*/
inline _Iter& operator++() { // pre-increment
mpNode = mpNode->getNext();
return *this;
}
const _Iter operator++(int) { // post-increment
_Iter tmp(*this);
mpNode = mpNode->getNext();
return tmp;
}
inline _Iter& operator--() { // pre-increment
mpNode = mpNode->getPrev();
return *this;
}
const _Iter operator--(int) { // post-increment
_Iter tmp(*this);
mpNode = mpNode->getPrev();
return tmp;
}
inline _NodePtr getNode() const { return mpNode; }
_NodePtr mpNode; /* should be private, but older gcc fails */
private:
friend class List;
};
public:
List() {
prep();
}
List(const List<T>& src) { // copy-constructor
prep();
insert(begin(), src.begin(), src.end());
}
virtual ~List() {
clear();
delete[] (unsigned char*) mpMiddle;
}
typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
List<T>& operator=(const List<T>& right);
/* returns true if the list is empty */
inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
/* return #of elements in list */
size_t size() const {
return size_t(distance(begin(), end()));
}
/*
* Return the first element or one past the last element. The
* _Node* we're returning is converted to an "iterator" by a
* constructor in _ListIterator.
*/
inline iterator begin() {
return iterator(mpMiddle->getNext());
}
inline const_iterator begin() const {
return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
}
inline iterator end() {
return iterator(mpMiddle);
}
inline const_iterator end() const {
return const_iterator(const_cast<_Node const*>(mpMiddle));
}
/* add the object to the head or tail of the list */
void push_front(const T& val) { insert(begin(), val); }
void push_back(const T& val) { insert(end(), val); }
/* insert before the current node; returns iterator at new node */
iterator insert(iterator posn, const T& val)
{
_Node* newNode = new _Node(val); // alloc & copy-construct
newNode->setNext(posn.getNode());
newNode->setPrev(posn.getNode()->getPrev());
posn.getNode()->getPrev()->setNext(newNode);
posn.getNode()->setPrev(newNode);
return iterator(newNode);
}
/* insert a range of elements before the current node */
void insert(iterator posn, const_iterator first, const_iterator last) {
for ( ; first != last; ++first)
insert(posn, *first);
}
/* remove one entry; returns iterator at next node */
iterator erase(iterator posn) {
_Node* pNext = posn.getNode()->getNext();
_Node* pPrev = posn.getNode()->getPrev();
pPrev->setNext(pNext);
pNext->setPrev(pPrev);
delete posn.getNode();
return iterator(pNext);
}
/* remove a range of elements */
iterator erase(iterator first, iterator last) {
while (first != last)
erase(first++); // don't erase than incr later!
return iterator(last);
}
/* remove all contents of the list */
void clear() {
_Node* pCurrent = mpMiddle->getNext();
_Node* pNext;
while (pCurrent != mpMiddle) {
pNext = pCurrent->getNext();
delete pCurrent;
pCurrent = pNext;
}
mpMiddle->setPrev(mpMiddle);
mpMiddle->setNext(mpMiddle);
}
/*
* Measure the distance between two iterators. On exist, "first"
* will be equal to "last". The iterators must refer to the same
* list.
*
* FIXME: This is actually a generic iterator function. It should be a
* template function at the top-level with specializations for things like
* vector<>, which can just do pointer math). Here we limit it to
* _ListIterator of the same type but different constness.
*/
template<
typename U,
template <class> class CL,
template <class> class CR
>
ptrdiff_t distance(
_ListIterator<U, CL> first, _ListIterator<U, CR> last) const
{
ptrdiff_t count = 0;
while (first != last) {
++first;
++count;
}
return count;
}
private:
/*
* I want a _Node but don't need it to hold valid data. More
* to the point, I don't want T's constructor to fire, since it
* might have side-effects or require arguments. So, we do this
* slightly uncouth storage alloc.
*/
void prep() {
mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
mpMiddle->setPrev(mpMiddle);
mpMiddle->setNext(mpMiddle);
}
/*
* This node plays the role of "pointer to head" and "pointer to tail".
* It sits in the middle of a circular list of nodes. The iterator
* runs around the circle until it encounters this one.
*/
_Node* mpMiddle;
};
/*
* Assignment operator.
*
* The simplest way to do this would be to clear out the target list and
* fill it with the source. However, we can speed things along by
* re-using existing elements.
*/
template<class T>
List<T>& List<T>::operator=(const List<T>& right)
{
if (this == &right)
return *this; // self-assignment
iterator firstDst = begin();
iterator lastDst = end();
const_iterator firstSrc = right.begin();
const_iterator lastSrc = right.end();
while (firstSrc != lastSrc && firstDst != lastDst)
*firstDst++ = *firstSrc++;
if (firstSrc == lastSrc) // ran out of elements in source?
erase(firstDst, lastDst); // yes, erase any extras
else
insert(lastDst, firstSrc, lastSrc); // copy remaining over
return *this;
}
}; // namespace android
#endif // _LIBS_UTILS_LIST_H

71
include/utils/Log.h Normal file
View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2005 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.
*/
//
// C/C++ logging functions. See the logging documentation for API details.
//
// We'd like these to be available from C code (in case we import some from
// somewhere), so this has a C interface.
//
// The output will be correct when the log file is shared between multiple
// threads and/or multiple processes so long as the operating system
// supports O_APPEND. These calls have mutex-protected data structures
// and so are NOT reentrant. Do not use LOG in a signal handler.
//
#ifndef _LIBS_UTILS_LOG_H
#define _LIBS_UTILS_LOG_H
#include <cutils/log.h>
#include <sys/types.h>
#ifdef __cplusplus
namespace android {
/*
* A very simple utility that yells in the log when an operation takes too long.
*/
class LogIfSlow {
public:
LogIfSlow(const char* tag, android_LogPriority priority,
int timeoutMillis, const char* message);
~LogIfSlow();
private:
const char* const mTag;
const android_LogPriority mPriority;
const int mTimeoutMillis;
const char* const mMessage;
const int64_t mStart;
};
/*
* Writes the specified debug log message if this block takes longer than the
* specified number of milliseconds to run. Includes the time actually taken.
*
* {
* ALOGD_IF_SLOW(50, "Excessive delay doing something.");
* doSomething();
* }
*/
#define ALOGD_IF_SLOW(timeoutMillis, message) \
android::LogIfSlow _logIfSlow(LOG_TAG, ANDROID_LOG_DEBUG, timeoutMillis, message);
} // namespace android
#endif // __cplusplus
#endif // _LIBS_UTILS_LOG_H

388
include/utils/Looper.h Normal file
View file

@ -0,0 +1,388 @@
/*
* Copyright (C) 2010 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 UTILS_LOOPER_H
#define UTILS_LOOPER_H
#include <utils/threads.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
#include <utils/Timers.h>
#include <android/looper.h>
#include <sys/epoll.h>
/*
* Declare a concrete type for the NDK's looper forward declaration.
*/
struct ALooper {
};
namespace android {
/**
* A message that can be posted to a Looper.
*/
struct Message {
Message() : what(0) { }
Message(int what) : what(what) { }
/* The message type. (interpretation is left up to the handler) */
int what;
};
/**
* Interface for a Looper message handler.
*
* The Looper holds a strong reference to the message handler whenever it has
* a message to deliver to it. Make sure to call Looper::removeMessages
* to remove any pending messages destined for the handler so that the handler
* can be destroyed.
*/
class MessageHandler : public virtual RefBase {
protected:
virtual ~MessageHandler() { }
public:
/**
* Handles a message.
*/
virtual void handleMessage(const Message& message) = 0;
};
/**
* A simple proxy that holds a weak reference to a message handler.
*/
class WeakMessageHandler : public MessageHandler {
protected:
virtual ~WeakMessageHandler();
public:
WeakMessageHandler(const wp<MessageHandler>& handler);
virtual void handleMessage(const Message& message);
private:
wp<MessageHandler> mHandler;
};
/**
* A looper callback.
*/
class LooperCallback : public virtual RefBase {
protected:
virtual ~LooperCallback() { }
public:
/**
* Handles a poll event for the given file descriptor.
* It is given the file descriptor it is associated with,
* a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT),
* and the data pointer that was originally supplied.
*
* Implementations should return 1 to continue receiving callbacks, or 0
* to have this file descriptor and callback unregistered from the looper.
*/
virtual int handleEvent(int fd, int events, void* data) = 0;
};
/**
* Wraps a ALooper_callbackFunc function pointer.
*/
class SimpleLooperCallback : public LooperCallback {
protected:
virtual ~SimpleLooperCallback();
public:
SimpleLooperCallback(ALooper_callbackFunc callback);
virtual int handleEvent(int fd, int events, void* data);
private:
ALooper_callbackFunc mCallback;
};
/**
* A polling loop that supports monitoring file descriptor events, optionally
* using callbacks. The implementation uses epoll() internally.
*
* A looper can be associated with a thread although there is no requirement that it must be.
*/
class Looper : public ALooper, public RefBase {
protected:
virtual ~Looper();
public:
/**
* Creates a looper.
*
* If allowNonCallbaks is true, the looper will allow file descriptors to be
* registered without associated callbacks. This assumes that the caller of
* pollOnce() is prepared to handle callback-less events itself.
*/
Looper(bool allowNonCallbacks);
/**
* Returns whether this looper instance allows the registration of file descriptors
* using identifiers instead of callbacks.
*/
bool getAllowNonCallbacks() const;
/**
* Waits for events to be available, with optional timeout in milliseconds.
* Invokes callbacks for all file descriptors on which an event occurred.
*
* If the timeout is zero, returns immediately without blocking.
* If the timeout is negative, waits indefinitely until an event appears.
*
* Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
* the timeout expired and no callbacks were invoked and no other file
* descriptors were ready.
*
* Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
*
* Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
* timeout expired.
*
* Returns ALOOPER_POLL_ERROR if an error occurred.
*
* Returns a value >= 0 containing an identifier if its file descriptor has data
* and it has no callback function (requiring the caller here to handle it).
* In this (and only this) case outFd, outEvents and outData will contain the poll
* events and data associated with the fd, otherwise they will be set to NULL.
*
* This method does not return until it has finished invoking the appropriate callbacks
* for all file descriptors that were signalled.
*/
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
/**
* Like pollOnce(), but performs all pending callbacks until all
* data has been consumed or a file descriptor is available with no callback.
* This function will never return ALOOPER_POLL_CALLBACK.
*/
int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollAll(int timeoutMillis) {
return pollAll(timeoutMillis, NULL, NULL, NULL);
}
/**
* Wakes the poll asynchronously.
*
* This method can be called on any thread.
* This method returns immediately.
*/
void wake();
/**
* Adds a new file descriptor to be polled by the looper.
* If the same file descriptor was previously added, it is replaced.
*
* "fd" is the file descriptor to be added.
* "ident" is an identifier for this event, which is returned from pollOnce().
* The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
* "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT.
* "callback" is the function to call when there is an event on the file descriptor.
* "data" is a private data pointer to supply to the callback.
*
* There are two main uses of this function:
*
* (1) If "callback" is non-NULL, then this function will be called when there is
* data on the file descriptor. It should execute any events it has pending,
* appropriately reading from the file descriptor. The 'ident' is ignored in this case.
*
* (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
* when its file descriptor has data available, requiring the caller to take
* care of processing it.
*
* Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
*
* This method can be called on any thread.
* This method may block briefly if it needs to wake the poll.
*
* The callback may either be specified as a bare function pointer or as a smart
* pointer callback object. The smart pointer should be preferred because it is
* easier to avoid races when the callback is removed from a different thread.
* See removeFd() for details.
*/
int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data);
int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);
/**
* Removes a previously added file descriptor from the looper.
*
* When this method returns, it is safe to close the file descriptor since the looper
* will no longer have a reference to it. However, it is possible for the callback to
* already be running or for it to run one last time if the file descriptor was already
* signalled. Calling code is responsible for ensuring that this case is safely handled.
* For example, if the callback takes care of removing itself during its own execution either
* by returning 0 or by calling this method, then it can be guaranteed to not be invoked
* again at any later time unless registered anew.
*
* A simple way to avoid this problem is to use the version of addFd() that takes
* a sp<LooperCallback> instead of a bare function pointer. The LooperCallback will
* be released at the appropriate time by the Looper.
*
* Returns 1 if the file descriptor was removed, 0 if none was previously registered.
*
* This method can be called on any thread.
* This method may block briefly if it needs to wake the poll.
*/
int removeFd(int fd);
/**
* Enqueues a message to be processed by the specified handler.
*
* The handler must not be null.
* This method can be called on any thread.
*/
void sendMessage(const sp<MessageHandler>& handler, const Message& message);
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* after the specified delay.
*
* The time delay is specified in uptime nanoseconds.
* The handler must not be null.
* This method can be called on any thread.
*/
void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
const Message& message);
/**
* Enqueues a message to be processed by the specified handler after all pending messages
* at the specified time.
*
* The time is specified in uptime nanoseconds.
* The handler must not be null.
* This method can be called on any thread.
*/
void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
const Message& message);
/**
* Removes all messages for the specified handler from the queue.
*
* The handler must not be null.
* This method can be called on any thread.
*/
void removeMessages(const sp<MessageHandler>& handler);
/**
* Removes all messages of a particular type for the specified handler from the queue.
*
* The handler must not be null.
* This method can be called on any thread.
*/
void removeMessages(const sp<MessageHandler>& handler, int what);
/**
* Return whether this looper's thread is currently idling -- that is, whether it
* stopped waiting for more work to do. Note that this is intrinsically racy, since
* its state can change before you get the result back.
*/
bool isIdling() const;
/**
* Prepares a looper associated with the calling thread, and returns it.
* If the thread already has a looper, it is returned. Otherwise, a new
* one is created, associated with the thread, and returned.
*
* The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
*/
static sp<Looper> prepare(int opts);
/**
* Sets the given looper to be associated with the calling thread.
* If another looper is already associated with the thread, it is replaced.
*
* If "looper" is NULL, removes the currently associated looper.
*/
static void setForThread(const sp<Looper>& looper);
/**
* Returns the looper associated with the calling thread, or NULL if
* there is not one.
*/
static sp<Looper> getForThread();
private:
struct Request {
int fd;
int ident;
sp<LooperCallback> callback;
void* data;
};
struct Response {
int events;
Request request;
};
struct MessageEnvelope {
MessageEnvelope() : uptime(0) { }
MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
const Message& message) : uptime(uptime), handler(handler), message(message) {
}
nsecs_t uptime;
sp<MessageHandler> handler;
Message message;
};
const bool mAllowNonCallbacks; // immutable
int mWakeReadPipeFd; // immutable
int mWakeWritePipeFd; // immutable
Mutex mLock;
Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
bool mSendingMessage; // guarded by mLock
// Whether we are currently waiting for work. Not protected by a lock,
// any use of it is racy anyway.
volatile bool mIdling;
int mEpollFd; // immutable
// Locked list of file descriptor monitoring requests.
KeyedVector<int, Request> mRequests; // guarded by mLock
// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
Vector<Response> mResponses;
size_t mResponseIndex;
nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
int pollInner(int timeoutMillis);
void awoken();
void pushResponse(int events, const Request& request);
static void initTLSKey();
static void threadDestructor(void *st);
};
} // namespace android
#endif // UTILS_LOOPER_H

237
include/utils/LruCache.h Normal file
View file

@ -0,0 +1,237 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_UTILS_LRU_CACHE_H
#define ANDROID_UTILS_LRU_CACHE_H
#include <utils/BasicHashtable.h>
#include <utils/UniquePtr.h>
namespace android {
/**
* GenerationCache callback used when an item is removed
*/
template<typename EntryKey, typename EntryValue>
class OnEntryRemoved {
public:
virtual ~OnEntryRemoved() { };
virtual void operator()(EntryKey& key, EntryValue& value) = 0;
}; // class OnEntryRemoved
template <typename TKey, typename TValue>
class LruCache {
public:
explicit LruCache(uint32_t maxCapacity);
enum Capacity {
kUnlimitedCapacity,
};
void setOnEntryRemovedListener(OnEntryRemoved<TKey, TValue>* listener);
size_t size() const;
const TValue& get(const TKey& key);
bool put(const TKey& key, const TValue& value);
bool remove(const TKey& key);
bool removeOldest();
void clear();
class Iterator {
public:
Iterator(const LruCache<TKey, TValue>& cache): mCache(cache), mIndex(-1) {
}
bool next() {
mIndex = mCache.mTable->next(mIndex);
return mIndex != -1;
}
size_t index() const {
return mIndex;
}
const TValue& value() const {
return mCache.mTable->entryAt(mIndex).value;
}
const TKey& key() const {
return mCache.mTable->entryAt(mIndex).key;
}
private:
const LruCache<TKey, TValue>& mCache;
size_t mIndex;
};
private:
LruCache(const LruCache& that); // disallow copy constructor
struct Entry {
TKey key;
TValue value;
Entry* parent;
Entry* child;
Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
}
const TKey& getKey() const { return key; }
};
void attachToCache(Entry& entry);
void detachFromCache(Entry& entry);
void rehash(size_t newCapacity);
UniquePtr<BasicHashtable<TKey, Entry> > mTable;
OnEntryRemoved<TKey, TValue>* mListener;
Entry* mOldest;
Entry* mYoungest;
uint32_t mMaxCapacity;
TValue mNullValue;
};
// Implementation is here, because it's fully templated
template <typename TKey, typename TValue>
LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
mNullValue(NULL), mTable(new BasicHashtable<TKey, Entry>), mYoungest(NULL), mOldest(NULL),
mListener(NULL) {
};
template<typename K, typename V>
void LruCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
mListener = listener;
}
template <typename TKey, typename TValue>
size_t LruCache<TKey, TValue>::size() const {
return mTable->size();
}
template <typename TKey, typename TValue>
const TValue& LruCache<TKey, TValue>::get(const TKey& key) {
hash_t hash = hash_type(key);
ssize_t index = mTable->find(-1, hash, key);
if (index == -1) {
return mNullValue;
}
Entry& entry = mTable->editEntryAt(index);
detachFromCache(entry);
attachToCache(entry);
return entry.value;
}
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::put(const TKey& key, const TValue& value) {
if (mMaxCapacity != kUnlimitedCapacity && size() >= mMaxCapacity) {
removeOldest();
}
hash_t hash = hash_type(key);
ssize_t index = mTable->find(-1, hash, key);
if (index >= 0) {
return false;
}
if (!mTable->hasMoreRoom()) {
rehash(mTable->capacity() * 2);
}
// Would it be better to initialize a blank entry and assign key, value?
Entry initEntry(key, value);
index = mTable->add(hash, initEntry);
Entry& entry = mTable->editEntryAt(index);
attachToCache(entry);
return true;
}
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::remove(const TKey& key) {
hash_t hash = hash_type(key);
ssize_t index = mTable->find(-1, hash, key);
if (index < 0) {
return false;
}
Entry& entry = mTable->editEntryAt(index);
if (mListener) {
(*mListener)(entry.key, entry.value);
}
detachFromCache(entry);
mTable->removeAt(index);
return true;
}
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::removeOldest() {
if (mOldest != NULL) {
return remove(mOldest->key);
// TODO: should probably abort if false
}
return false;
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::clear() {
if (mListener) {
for (Entry* p = mOldest; p != NULL; p = p->child) {
(*mListener)(p->key, p->value);
}
}
mYoungest = NULL;
mOldest = NULL;
mTable->clear();
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::attachToCache(Entry& entry) {
if (mYoungest == NULL) {
mYoungest = mOldest = &entry;
} else {
entry.parent = mYoungest;
mYoungest->child = &entry;
mYoungest = &entry;
}
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::detachFromCache(Entry& entry) {
if (entry.parent != NULL) {
entry.parent->child = entry.child;
} else {
mOldest = entry.child;
}
if (entry.child != NULL) {
entry.child->parent = entry.parent;
} else {
mYoungest = entry.parent;
}
entry.parent = NULL;
entry.child = NULL;
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::rehash(size_t newCapacity) {
UniquePtr<BasicHashtable<TKey, Entry> > oldTable(mTable.release());
Entry* oldest = mOldest;
mOldest = NULL;
mYoungest = NULL;
mTable.reset(new BasicHashtable<TKey, Entry>(newCapacity));
for (Entry* p = oldest; p != NULL; p = p->child) {
put(p->key, p->value);
}
}
}
#endif // ANDROID_UTILS_LRU_CACHE_H

137
include/utils/Mutex.h Normal file
View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 2007 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 _LIBS_UTILS_MUTEX_H
#define _LIBS_UTILS_MUTEX_H
#include <stdint.h>
#include <sys/types.h>
#include <time.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
#endif
#include <utils/Errors.h>
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
class Condition;
/*
* Simple mutex class. The implementation is system-dependent.
*
* The mutex must be unlocked by the thread that locked it. They are not
* recursive, i.e. the same thread can't lock it multiple times.
*/
class Mutex {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
Mutex();
Mutex(const char* name);
Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
status_t lock();
void unlock();
// lock if possible; returns 0 on success, error otherwise
status_t tryLock();
// Manages the mutex automatically. It'll be locked when Autolock is
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
private:
friend class Condition;
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
#if defined(HAVE_PTHREADS)
pthread_mutex_t mMutex;
#else
void _init();
void* mState;
#endif
};
// ---------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&mMutex, &attr);
pthread_mutexattr_destroy(&attr);
} else {
pthread_mutex_init(&mMutex, NULL);
}
}
inline Mutex::~Mutex() {
pthread_mutex_destroy(&mMutex);
}
inline status_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
inline status_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
#endif // HAVE_PTHREADS
// ---------------------------------------------------------------------------
/*
* Automatic mutex. Declare one of these at the top of a function.
* When the function returns, it will go out of scope, and release the
* mutex.
*/
typedef Mutex::Autolock AutoMutex;
// ---------------------------------------------------------------------------
}; // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_MUTEX_H

106
include/utils/PropertyMap.h Normal file
View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2010 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 _UTILS_PROPERTY_MAP_H
#define _UTILS_PROPERTY_MAP_H
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
namespace android {
/*
* Provides a mechanism for passing around string-based property key / value pairs
* and loading them from property files.
*
* The property files have the following simple structure:
*
* # Comment
* key = value
*
* Keys and values are any sequence of printable ASCII characters.
* The '=' separates the key from the value.
* The key and value may not contain whitespace.
*
* The '\' character is reserved for escape sequences and is not currently supported.
* The '"" character is reserved for quoting and is not currently supported.
* Files that contain the '\' or '"' character will fail to parse.
*
* The file must not contain duplicate keys.
*
* TODO Support escape sequences and quoted values when needed.
*/
class PropertyMap {
public:
/* Creates an empty property map. */
PropertyMap();
~PropertyMap();
/* Clears the property map. */
void clear();
/* Adds a property.
* Replaces the property with the same key if it is already present.
*/
void addProperty(const String8& key, const String8& value);
/* Returns true if the property map contains the specified key. */
bool hasProperty(const String8& key) const;
/* Gets the value of a property and parses it.
* Returns true and sets outValue if the key was found and its value was parsed successfully.
* Otherwise returns false and does not modify outValue. (Also logs a warning.)
*/
bool tryGetProperty(const String8& key, String8& outValue) const;
bool tryGetProperty(const String8& key, bool& outValue) const;
bool tryGetProperty(const String8& key, int32_t& outValue) const;
bool tryGetProperty(const String8& key, float& outValue) const;
/* Adds all values from the specified property map. */
void addAll(const PropertyMap* map);
/* Gets the underlying property map. */
inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
/* Loads a property map from a file. */
static status_t load(const String8& filename, PropertyMap** outMap);
private:
class Parser {
PropertyMap* mMap;
Tokenizer* mTokenizer;
public:
Parser(PropertyMap* map, Tokenizer* tokenizer);
~Parser();
status_t parse();
private:
status_t parseType();
status_t parseKey();
status_t parseKeyProperty();
status_t parseModifier(const String8& token, int32_t* outMetaState);
status_t parseCharacterLiteral(char16_t* outCharacter);
};
KeyedVector<String8, String8> mProperties;
};
} // namespace android
#endif // _UTILS_PROPERTY_MAP_H

126
include/utils/RWLock.h Normal file
View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2007 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 _LIBS_UTILS_RWLOCK_H
#define _LIBS_UTILS_RWLOCK_H
#include <stdint.h>
#include <sys/types.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
#endif
#include <utils/Errors.h>
#include <utils/ThreadDefs.h>
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
/*
* Simple mutex class. The implementation is system-dependent.
*
* The mutex must be unlocked by the thread that locked it. They are not
* recursive, i.e. the same thread can't lock it multiple times.
*/
class RWLock {
public:
enum {
PRIVATE = 0,
SHARED = 1
};
RWLock();
RWLock(const char* name);
RWLock(int type, const char* name = NULL);
~RWLock();
status_t readLock();
status_t tryReadLock();
status_t writeLock();
status_t tryWriteLock();
void unlock();
class AutoRLock {
public:
inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); }
inline ~AutoRLock() { mLock.unlock(); }
private:
RWLock& mLock;
};
class AutoWLock {
public:
inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); }
inline ~AutoWLock() { mLock.unlock(); }
private:
RWLock& mLock;
};
private:
// A RWLock cannot be copied
RWLock(const RWLock&);
RWLock& operator = (const RWLock&);
pthread_rwlock_t mRWLock;
};
inline RWLock::RWLock() {
pthread_rwlock_init(&mRWLock, NULL);
}
inline RWLock::RWLock(__attribute__((unused)) const char* name) {
pthread_rwlock_init(&mRWLock, NULL);
}
inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_rwlock_init(&mRWLock, &attr);
pthread_rwlockattr_destroy(&attr);
} else {
pthread_rwlock_init(&mRWLock, NULL);
}
}
inline RWLock::~RWLock() {
pthread_rwlock_destroy(&mRWLock);
}
inline status_t RWLock::readLock() {
return -pthread_rwlock_rdlock(&mRWLock);
}
inline status_t RWLock::tryReadLock() {
return -pthread_rwlock_tryrdlock(&mRWLock);
}
inline status_t RWLock::writeLock() {
return -pthread_rwlock_wrlock(&mRWLock);
}
inline status_t RWLock::tryWriteLock() {
return -pthread_rwlock_trywrlock(&mRWLock);
}
inline void RWLock::unlock() {
pthread_rwlock_unlock(&mRWLock);
}
#endif // HAVE_PTHREADS
// ---------------------------------------------------------------------------
}; // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_RWLOCK_H

546
include/utils/RefBase.h Normal file
View file

@ -0,0 +1,546 @@
/*
* Copyright (C) 2005 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_REF_BASE_H
#define ANDROID_REF_BASE_H
#include <cutils/atomic.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <utils/StrongPointer.h>
#include <utils/TypeHelpers.h>
// ---------------------------------------------------------------------------
namespace android {
class TextOutput;
TextOutput& printWeakPointer(TextOutput& to, const void* val);
// ---------------------------------------------------------------------------
#define COMPARE_WEAK(_op_) \
inline bool operator _op_ (const sp<T>& o) const { \
return m_ptr _op_ o.m_ptr; \
} \
inline bool operator _op_ (const T* o) const { \
return m_ptr _op_ o; \
} \
template<typename U> \
inline bool operator _op_ (const sp<U>& o) const { \
return m_ptr _op_ o.m_ptr; \
} \
template<typename U> \
inline bool operator _op_ (const U* o) const { \
return m_ptr _op_ o; \
}
// ---------------------------------------------------------------------------
class ReferenceRenamer {
protected:
// destructor is purposedly not virtual so we avoid code overhead from
// subclasses; we have to make it protected to guarantee that it
// cannot be called from this base class (and to make strict compilers
// happy).
~ReferenceRenamer() { }
public:
virtual void operator()(size_t i) const = 0;
};
// ---------------------------------------------------------------------------
class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
//! DEBUGGING ONLY: Get current strong ref count.
int32_t getStrongCount() const;
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
// acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
// acquires a weak reference if there is already one.
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
// for proper use.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
int32_t getWeakCount() const;
//! DEBUGGING ONLY: Print references held on object.
void printRefs() const;
//! DEBUGGING ONLY: Enable tracking for this object.
// enable -- enable/disable tracking
// retain -- when tracking is enable, if true, then we save a stack trace
// for each reference and dereference; when retain == false, we
// match up references and dereferences and keep only the
// outstanding ones.
void trackMe(bool enable, bool retain);
};
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
//! DEBUGGING ONLY: Print references held on object.
inline void printRefs() const { getWeakRefs()->printRefs(); }
//! DEBUGGING ONLY: Enable tracking of object.
inline void trackMe(bool enable, bool retain)
{
getWeakRefs()->trackMe(enable, retain);
}
typedef RefBase basetype;
protected:
RefBase();
virtual ~RefBase();
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
void extendObjectLifetime(int32_t mode);
//! Flags for onIncStrongAttempted()
enum {
FIRST_INC_STRONG = 0x0001
};
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
virtual void onLastWeakRef(const void* id);
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
private:
friend class ReferenceMover;
static void renameRefs(size_t n, const ReferenceRenamer& renamer);
static void renameRefId(weakref_type* ref,
const void* old_id, const void* new_id);
static void renameRefId(RefBase* ref,
const void* old_id, const void* new_id);
weakref_impl* const mRefs;
};
// ---------------------------------------------------------------------------
template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(__attribute__((unused)) const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(__attribute__((unused)) const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
}
typedef LightRefBase<T> basetype;
protected:
inline ~LightRefBase() { }
private:
friend class ReferenceMover;
inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
inline static void renameRefId(T* ref,
const void* old_id, const void* new_id) { }
private:
mutable volatile int32_t mCount;
};
// ---------------------------------------------------------------------------
template <typename T>
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
wp(T* other);
wp(const wp<T>& other);
wp(const sp<T>& other);
template<typename U> wp(U* other);
template<typename U> wp(const sp<U>& other);
template<typename U> wp(const wp<U>& other);
~wp();
// Assignment
wp& operator = (T* other);
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
template<typename U> wp& operator = (U* other);
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
void set_object_and_refs(T* other, weakref_type* refs);
// promotion to sp
sp<T> promote() const;
// Reset
void clear();
// Accessors
inline weakref_type* get_refs() const { return m_refs; }
inline T* unsafe_get() const { return m_ptr; }
// Operators
COMPARE_WEAK(==)
COMPARE_WEAK(!=)
COMPARE_WEAK(>)
COMPARE_WEAK(<)
COMPARE_WEAK(<=)
COMPARE_WEAK(>=)
inline bool operator == (const wp<T>& o) const {
return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
}
template<typename U>
inline bool operator == (const wp<U>& o) const {
return m_ptr == o.m_ptr;
}
inline bool operator > (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
template<typename U>
inline bool operator > (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
inline bool operator < (const wp<T>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
template<typename U>
inline bool operator < (const wp<U>& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
T* m_ptr;
weakref_type* m_refs;
};
template <typename T>
TextOutput& operator<<(TextOutput& to, const wp<T>& val);
#undef COMPARE_WEAK
// ---------------------------------------------------------------------------
// No user serviceable parts below here.
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
template<typename T>
wp<T>::wp(const wp<T>& other)
: m_ptr(other.m_ptr), m_refs(other.m_refs)
{
if (m_ptr) m_refs->incWeak(this);
}
template<typename T>
wp<T>::wp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
template<typename T> template<typename U>
wp<T>::wp(U* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
template<typename T> template<typename U>
wp<T>::wp(const wp<U>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = other.m_refs;
m_refs->incWeak(this);
}
}
template<typename T> template<typename U>
wp<T>::wp(const sp<U>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
template<typename T>
wp<T>& wp<T>::operator = (T* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : 0;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
return *this;
}
template<typename T>
wp<T>& wp<T>::operator = (const wp<T>& other)
{
weakref_type* otherRefs(other.m_refs);
T* otherPtr(other.m_ptr);
if (otherPtr) otherRefs->incWeak(this);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = otherRefs;
return *this;
}
template<typename T>
wp<T>& wp<T>::operator = (const sp<T>& other)
{
weakref_type* newRefs =
other != NULL ? other->createWeak(this) : 0;
T* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = newRefs;
return *this;
}
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (U* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : 0;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
return *this;
}
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const wp<U>& other)
{
weakref_type* otherRefs(other.m_refs);
U* otherPtr(other.m_ptr);
if (otherPtr) otherRefs->incWeak(this);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = otherRefs;
return *this;
}
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const sp<U>& other)
{
weakref_type* newRefs =
other != NULL ? other->createWeak(this) : 0;
U* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = newRefs;
return *this;
}
template<typename T>
void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
{
if (other) refs->incWeak(this);
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = refs;
}
template<typename T>
sp<T> wp<T>::promote() const
{
sp<T> result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
template<typename T>
void wp<T>::clear()
{
if (m_ptr) {
m_refs->decWeak(this);
m_ptr = 0;
}
}
template <typename T>
inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
{
return printWeakPointer(to, val.unsafe_get());
}
// ---------------------------------------------------------------------------
// this class just serves as a namespace so TYPE::moveReferences can stay
// private.
class ReferenceMover {
public:
// it would be nice if we could make sure no extra code is generated
// for sp<TYPE> or wp<TYPE> when TYPE is a descendant of RefBase:
// Using a sp<RefBase> override doesn't work; it's a bit like we wanted
// a template<typename TYPE inherits RefBase> template...
template<typename TYPE> static inline
void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
class Renamer : public ReferenceRenamer {
sp<TYPE>* d;
sp<TYPE> const* s;
virtual void operator()(size_t i) const {
// The id are known to be the sp<>'s this pointer
TYPE::renameRefId(d[i].get(), &s[i], &d[i]);
}
public:
Renamer(sp<TYPE>* d, sp<TYPE> const* s) : s(s), d(d) { }
};
memmove(d, s, n*sizeof(sp<TYPE>));
TYPE::renameRefs(n, Renamer(d, s));
}
template<typename TYPE> static inline
void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
class Renamer : public ReferenceRenamer {
wp<TYPE>* d;
wp<TYPE> const* s;
virtual void operator()(size_t i) const {
// The id are known to be the wp<>'s this pointer
TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]);
}
public:
Renamer(wp<TYPE>* d, wp<TYPE> const* s) : s(s), d(d) { }
};
memmove(d, s, n*sizeof(wp<TYPE>));
TYPE::renameRefs(n, Renamer(d, s));
}
};
// specialization for moving sp<> and wp<> types.
// these are used by the [Sorted|Keyed]Vector<> implementations
// sp<> and wp<> need to be handled specially, because they do not
// have trivial copy operation in the general case (see RefBase.cpp
// when DEBUG ops are enabled), but can be implemented very
// efficiently in most cases.
template<typename TYPE> inline
void move_forward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
ReferenceMover::move_references(d, s, n);
}
template<typename TYPE> inline
void move_backward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
ReferenceMover::move_references(d, s, n);
}
template<typename TYPE> inline
void move_forward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
ReferenceMover::move_references(d, s, n);
}
template<typename TYPE> inline
void move_backward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
ReferenceMover::move_references(d, s, n);
}
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_REF_BASE_H

View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 2005 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_SHARED_BUFFER_H
#define ANDROID_SHARED_BUFFER_H
#include <stdint.h>
#include <sys/types.h>
// ---------------------------------------------------------------------------
namespace android {
class SharedBuffer
{
public:
/* flags to use with release() */
enum {
eKeepStorage = 0x00000001
};
/*! allocate a buffer of size 'size' and acquire() it.
* call release() to free it.
*/
static SharedBuffer* alloc(size_t size);
/*! free the memory associated with the SharedBuffer.
* Fails if there are any users associated with this SharedBuffer.
* In other words, the buffer must have been release by all its
* users.
*/
static ssize_t dealloc(const SharedBuffer* released);
//! access the data for read
inline const void* data() const;
//! access the data for read/write
inline void* data();
//! get size of the buffer
inline size_t size() const;
//! get back a SharedBuffer object from its data
static inline SharedBuffer* bufferFromData(void* data);
//! get back a SharedBuffer object from its data
static inline const SharedBuffer* bufferFromData(const void* data);
//! get the size of a SharedBuffer object from its data
static inline size_t sizeFromData(const void* data);
//! edit the buffer (get a writtable, or non-const, version of it)
SharedBuffer* edit() const;
//! edit the buffer, resizing if needed
SharedBuffer* editResize(size_t size) const;
//! like edit() but fails if a copy is required
SharedBuffer* attemptEdit() const;
//! resize and edit the buffer, loose it's content.
SharedBuffer* reset(size_t size) const;
//! acquire/release a reference on this buffer
void acquire() const;
/*! release a reference on this buffer, with the option of not
* freeing the memory associated with it if it was the last reference
* returns the previous reference count
*/
int32_t release(uint32_t flags = 0) const;
//! returns wether or not we're the only owner
inline bool onlyOwner() const;
private:
inline SharedBuffer() { }
inline ~SharedBuffer() { }
SharedBuffer(const SharedBuffer&);
SharedBuffer& operator = (const SharedBuffer&);
// 16 bytes. must be sized to preserve correct alignment.
mutable int32_t mRefs;
size_t mSize;
uint32_t mReserved[2];
};
// ---------------------------------------------------------------------------
const void* SharedBuffer::data() const {
return this + 1;
}
void* SharedBuffer::data() {
return this + 1;
}
size_t SharedBuffer::size() const {
return mSize;
}
SharedBuffer* SharedBuffer::bufferFromData(void* data) {
return data ? static_cast<SharedBuffer *>(data)-1 : 0;
}
const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
return data ? static_cast<const SharedBuffer *>(data)-1 : 0;
}
size_t SharedBuffer::sizeFromData(const void* data) {
return data ? bufferFromData(data)->mSize : 0;
}
bool SharedBuffer::onlyOwner() const {
return (mRefs == 1);
}
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_VECTOR_H

77
include/utils/Singleton.h Normal file
View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2007 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_UTILS_SINGLETON_H
#define ANDROID_UTILS_SINGLETON_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
#include <cutils/compiler.h>
namespace android {
// ---------------------------------------------------------------------------
template <typename TYPE>
class ANDROID_API Singleton
{
public:
static TYPE& getInstance() {
Mutex::Autolock _l(sLock);
TYPE* instance = sInstance;
if (instance == 0) {
instance = new TYPE();
sInstance = instance;
}
return *instance;
}
static bool hasInstance() {
Mutex::Autolock _l(sLock);
return sInstance != 0;
}
protected:
~Singleton() { };
Singleton() { };
private:
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
static Mutex sLock;
static TYPE* sInstance;
};
/*
* use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
* (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
* and avoid to have a copy of them in each compilation units Singleton<TYPE>
* is used.
* NOTE: we use a version of Mutex ctor that takes a parameter, because
* for some unknown reason using the default ctor doesn't emit the variable!
*/
#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE); \
template<> TYPE* Singleton< TYPE >::sInstance(0); \
template class Singleton< TYPE >;
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_UTILS_SINGLETON_H

Some files were not shown because too many files have changed in this diff Show more