Merge commit '536dea9d61a032e64bbe584a97463c6638ead009' into HEAD
Change-Id: I5c469a4b738629d99d721cad7ded02d6c35f56d5
This commit is contained in:
commit
66ed50af68
215 changed files with 24509 additions and 4723 deletions
|
|
@ -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)/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
0
MODULE_LICENSE_APACHE2
Normal file
324
NOTICE
Normal file
324
NOTICE
Normal 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.
|
||||||
|
|
@ -64,7 +64,6 @@ LOCAL_SRC_FILES := \
|
||||||
file_sync_client.c \
|
file_sync_client.c \
|
||||||
$(EXTRA_SRCS) \
|
$(EXTRA_SRCS) \
|
||||||
$(USB_SRCS) \
|
$(USB_SRCS) \
|
||||||
utils.c \
|
|
||||||
usb_vendors.c
|
usb_vendors.c
|
||||||
|
|
||||||
LOCAL_C_INCLUDES += external/openssl/include
|
LOCAL_C_INCLUDES += external/openssl/include
|
||||||
|
|
@ -116,8 +115,7 @@ LOCAL_SRC_FILES := \
|
||||||
framebuffer_service.c \
|
framebuffer_service.c \
|
||||||
remount_service.c \
|
remount_service.c \
|
||||||
usb_linux_client.c \
|
usb_linux_client.c \
|
||||||
log_service.c \
|
log_service.c
|
||||||
utils.c
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
|
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
|
||||||
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
|
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_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
|
||||||
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
|
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
|
LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -157,7 +155,6 @@ LOCAL_SRC_FILES := \
|
||||||
file_sync_client.c \
|
file_sync_client.c \
|
||||||
get_my_path_linux.c \
|
get_my_path_linux.c \
|
||||||
usb_linux.c \
|
usb_linux.c \
|
||||||
utils.c \
|
|
||||||
usb_vendors.c \
|
usb_vendors.c \
|
||||||
fdevent.c
|
fdevent.c
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,27 +225,6 @@ framebuffer:
|
||||||
If the adbd daemon doesn't have sufficient privileges to open
|
If the adbd daemon doesn't have sufficient privileges to open
|
||||||
the framebuffer device, the connection is simply closed immediately.
|
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>
|
jdwp:<pid>
|
||||||
Connects to the JDWP thread running in the VM of process <pid>.
|
Connects to the JDWP thread running in the VM of process <pid>.
|
||||||
|
|
||||||
|
|
|
||||||
134
adb/adb.c
134
adb/adb.c
|
|
@ -34,6 +34,7 @@
|
||||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
#if !ADB_HOST
|
#if !ADB_HOST
|
||||||
|
#include <cutils/properties.h>
|
||||||
#include <private/android_filesystem_config.h>
|
#include <private/android_filesystem_config.h>
|
||||||
#include <sys/capability.h>
|
#include <sys/capability.h>
|
||||||
#include <linux/prctl.h>
|
#include <linux/prctl.h>
|
||||||
|
|
@ -1199,7 +1200,7 @@ static void drop_capabilities_bounding_set_if_needed() {
|
||||||
#endif
|
#endif
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; 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
|
// CAP_SETUID CAP_SETGID needed by /system/bin/run-as
|
||||||
continue;
|
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 listen on a port (default 5037) if running in secure mode */
|
||||||
/* don't run as root if we are running in secure mode */
|
/* don't run as root if we are running in secure mode */
|
||||||
if (should_drop_privileges()) {
|
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();
|
drop_capabilities_bounding_set_if_needed();
|
||||||
|
|
||||||
/* add extra groups:
|
/* add extra groups:
|
||||||
|
|
@ -1337,16 +1331,6 @@ int adb_main(int is_daemon, int server_port)
|
||||||
exit(1);
|
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");
|
D("Local port disabled\n");
|
||||||
} else {
|
} else {
|
||||||
char local_name[30];
|
char local_name[30];
|
||||||
|
|
@ -1404,105 +1388,6 @@ int adb_main(int is_daemon, int server_port)
|
||||||
return 0;
|
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)
|
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
|
||||||
{
|
{
|
||||||
atransport *transport = NULL;
|
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
|
// remove TCP transport
|
||||||
if (!strncmp(service, "disconnect:", 11)) {
|
if (!strncmp(service, "disconnect:", 11)) {
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
|
|
|
||||||
|
|
@ -128,10 +128,7 @@ struct asocket {
|
||||||
*/
|
*/
|
||||||
void (*close)(asocket *s);
|
void (*close)(asocket *s);
|
||||||
|
|
||||||
/* socket-type-specific extradata */
|
/* A socket is bound to atransport */
|
||||||
void *extra;
|
|
||||||
|
|
||||||
/* A socket is bound to atransport */
|
|
||||||
atransport *transport;
|
atransport *transport;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -292,7 +289,7 @@ void init_usb_transport(atransport *t, usb_handle *usb, int state);
|
||||||
void close_usb_devices();
|
void close_usb_devices();
|
||||||
|
|
||||||
/* cause new transports to be init'd and added to the list */
|
/* 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 */
|
/* these should only be used for the "adb disconnect" command */
|
||||||
void unregister_transport(atransport *t);
|
void unregister_transport(atransport *t);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <cutils/logger.h>
|
#include <log/logger.h>
|
||||||
#include "sysdeps.h"
|
#include "sysdeps.h"
|
||||||
#include "adb.h"
|
#include "adb.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
#ifndef ADB_MUTEX
|
#ifndef ADB_MUTEX
|
||||||
#error ADB_MUTEX not defined when including this file
|
#error ADB_MUTEX not defined when including this file
|
||||||
#endif
|
#endif
|
||||||
ADB_MUTEX(dns_lock)
|
|
||||||
ADB_MUTEX(socket_list_lock)
|
ADB_MUTEX(socket_list_lock)
|
||||||
ADB_MUTEX(transport_lock)
|
ADB_MUTEX(transport_lock)
|
||||||
#if ADB_HOST
|
#if ADB_HOST
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ static char *find_mount(const char *dir)
|
||||||
static int remount_system()
|
static int remount_system()
|
||||||
{
|
{
|
||||||
char *dev;
|
char *dev;
|
||||||
|
int fd;
|
||||||
|
int OFF = 0;
|
||||||
|
|
||||||
if (system_ro == 0) {
|
if (system_ro == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -82,6 +84,13 @@ static int remount_system()
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -1;
|
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);
|
system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
|
||||||
|
|
||||||
free(dev);
|
free(dev);
|
||||||
|
|
|
||||||
240
adb/services.c
240
adb/services.c
|
|
@ -14,6 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -34,6 +35,7 @@
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# include <cutils/android_reboot.h>
|
# include <cutils/android_reboot.h>
|
||||||
|
# include <cutils/properties.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct stinfo stinfo;
|
typedef struct stinfo stinfo;
|
||||||
|
|
@ -53,59 +55,7 @@ void *service_bootstrap_func(void *x)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ADB_HOST
|
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void restart_root_service(int fd, void *cookie)
|
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)
|
void reboot_service(int fd, void *arg)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
char property_val[PROPERTY_VALUE_MAX];
|
||||||
int pid, ret;
|
int pid, ret;
|
||||||
|
|
||||||
sync();
|
sync();
|
||||||
|
|
@ -182,51 +133,25 @@ void reboot_service(int fd, void *arg)
|
||||||
waitpid(pid, &ret, 0);
|
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) {
|
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));
|
writex(fd, buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
cleanup:
|
||||||
free(arg);
|
free(arg);
|
||||||
adb_close(fd);
|
adb_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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)
|
static int create_service_thread(void (*func)(int, void *), void *cookie)
|
||||||
{
|
{
|
||||||
stinfo *sti;
|
stinfo *sti;
|
||||||
|
|
@ -413,9 +338,7 @@ int service_to_fd(const char *name)
|
||||||
disable_tcp_nagle(ret);
|
disable_tcp_nagle(ret);
|
||||||
} else {
|
} else {
|
||||||
#if ADB_HOST
|
#if ADB_HOST
|
||||||
adb_mutex_lock(&dns_lock);
|
|
||||||
ret = socket_network_client(name + 1, port, SOCK_STREAM);
|
ret = socket_network_client(name + 1, port, SOCK_STREAM);
|
||||||
adb_mutex_unlock(&dns_lock);
|
|
||||||
#else
|
#else
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -434,18 +357,11 @@ int service_to_fd(const char *name)
|
||||||
ret = socket_local_client(name + 16,
|
ret = socket_local_client(name + 16,
|
||||||
ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
|
ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
|
||||||
#endif
|
#endif
|
||||||
#if ADB_HOST
|
#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 */
|
|
||||||
} else if(!strncmp("dev:", name, 4)) {
|
} else if(!strncmp("dev:", name, 4)) {
|
||||||
ret = unix_open(name + 4, O_RDWR);
|
ret = unix_open(name + 4, O_RDWR);
|
||||||
} else if(!strncmp(name, "framebuffer:", 12)) {
|
} else if(!strncmp(name, "framebuffer:", 12)) {
|
||||||
ret = create_service_thread(framebuffer_service, 0);
|
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)) {
|
} else if (!strncmp(name, "jdwp:", 5)) {
|
||||||
ret = create_jdwp_connection_fd(atoi(name+5));
|
ret = create_jdwp_connection_fd(atoi(name+5));
|
||||||
} else if (!strncmp(name, "log:", 4)) {
|
} 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);
|
ret = create_service_thread(restart_tcp_service, (void *)port);
|
||||||
} else if(!strncmp(name, "usb:", 4)) {
|
} else if(!strncmp(name, "usb:", 4)) {
|
||||||
ret = create_service_thread(restart_usb_service, NULL);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
|
|
@ -519,6 +431,124 @@ static void wait_for_state(int fd, void* cookie)
|
||||||
adb_close(fd);
|
adb_close(fd);
|
||||||
D("wait_for_state is done\n");
|
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
|
#endif
|
||||||
|
|
||||||
#if ADB_HOST
|
#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);
|
int fd = create_service_thread(wait_for_state, sinfo);
|
||||||
return create_local_socket(fd);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -844,7 +844,7 @@ static void smart_socket_close(asocket *s)
|
||||||
free(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");
|
D("Creating smart socket \n");
|
||||||
asocket *s = calloc(1, sizeof(asocket));
|
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->enqueue = smart_socket_enqueue;
|
||||||
s->ready = smart_socket_ready;
|
s->ready = smart_socket_ready;
|
||||||
s->close = smart_socket_close;
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void smart_socket_action(asocket *s, const char *act)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void connect_to_smartsocket(asocket *s)
|
void connect_to_smartsocket(asocket *s)
|
||||||
{
|
{
|
||||||
D("Connecting to smart socket \n");
|
D("Connecting to smart socket \n");
|
||||||
asocket *ss = create_smart_socket(smart_socket_action);
|
asocket *ss = create_smart_socket();
|
||||||
s->peer = ss;
|
s->peer = ss;
|
||||||
ss->peer = s;
|
ss->peer = s;
|
||||||
s->ready(s);
|
s->ready(s);
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,6 @@ extern char* adb_strtok_r(char *str, const char *delim, char **saveptr);
|
||||||
|
|
||||||
#include "fdevent.h"
|
#include "fdevent.h"
|
||||||
#include <cutils/sockets.h>
|
#include <cutils/sockets.h>
|
||||||
#include <cutils/properties.h>
|
|
||||||
#include <cutils/misc.h>
|
#include <cutils/misc.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,11 @@ static atransport transport_list = {
|
||||||
.prev = &transport_list,
|
.prev = &transport_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static atransport pending_list = {
|
||||||
|
.next = &pending_list,
|
||||||
|
.prev = &pending_list,
|
||||||
|
};
|
||||||
|
|
||||||
ADB_MUTEX_DEFINE( transport_lock );
|
ADB_MUTEX_DEFINE( transport_lock );
|
||||||
|
|
||||||
#if ADB_TRACE
|
#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);
|
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->next = &transport_list;
|
||||||
t->prev = transport_list.prev;
|
t->prev = transport_list.prev;
|
||||||
t->next->prev = t;
|
t->next->prev = t;
|
||||||
|
|
@ -989,9 +997,10 @@ void close_usb_devices()
|
||||||
}
|
}
|
||||||
#endif // ADB_HOST
|
#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 *t = calloc(1, sizeof(atransport));
|
||||||
|
atransport *n;
|
||||||
char buff[32];
|
char buff[32];
|
||||||
|
|
||||||
if (!serial) {
|
if (!serial) {
|
||||||
|
|
@ -999,15 +1008,37 @@ void register_socket_transport(int s, const char *serial, int port, int local)
|
||||||
serial = buff;
|
serial = buff;
|
||||||
}
|
}
|
||||||
D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
|
D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
|
||||||
if ( init_socket_transport(t, s, port, local) < 0 ) {
|
if (init_socket_transport(t, s, port, local) < 0) {
|
||||||
adb_close(s);
|
|
||||||
free(t);
|
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);
|
register_transport(t);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ADB_HOST
|
#if ADB_HOST
|
||||||
|
|
@ -1077,6 +1108,14 @@ void register_usb_transport(usb_handle *usb, const char *serial, const char *dev
|
||||||
if(devpath) {
|
if(devpath) {
|
||||||
t->devpath = strdup(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);
|
register_transport(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@
|
||||||
|
|
||||||
#include "sysdeps.h"
|
#include "sysdeps.h"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#if !ADB_HOST
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TRACE_TAG TRACE_TRANSPORT
|
#define TRACE_TAG TRACE_TRANSPORT
|
||||||
#include "adb.h"
|
#include "adb.h"
|
||||||
|
|
|
||||||
106
adb/utils.c
106
adb/utils.c
|
|
@ -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;
|
|
||||||
}
|
|
||||||
68
adb/utils.h
68
adb/utils.h
|
|
@ -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 */
|
|
||||||
|
|
@ -31,9 +31,10 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#include <log/logd.h>
|
||||||
|
#include <log/logger.h>
|
||||||
|
|
||||||
#include <cutils/sockets.h>
|
#include <cutils/sockets.h>
|
||||||
#include <cutils/logd.h>
|
|
||||||
#include <cutils/logger.h>
|
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
#include <cutils/debugger.h>
|
#include <cutils/debugger.h>
|
||||||
|
|
||||||
|
|
@ -435,11 +436,13 @@ static int do_server() {
|
||||||
signal(SIGBUS, SIG_DFL);
|
signal(SIGBUS, SIG_DFL);
|
||||||
signal(SIGFPE, SIG_DFL);
|
signal(SIGFPE, SIG_DFL);
|
||||||
signal(SIGSEGV, SIG_DFL);
|
signal(SIGSEGV, SIG_DFL);
|
||||||
signal(SIGPIPE, SIG_DFL);
|
|
||||||
#ifdef SIGSTKFLT
|
#ifdef SIGSTKFLT
|
||||||
signal(SIGSTKFLT, SIG_DFL);
|
signal(SIGSTKFLT, SIG_DFL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Ignore failed writes to closed sockets
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
logsocket = socket_local_client("logd",
|
logsocket = socket_local_client("logd",
|
||||||
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
|
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
|
||||||
if(logsocket < 0) {
|
if(logsocket < 0) {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
#include <private/android_filesystem_config.h>
|
#include <private/android_filesystem_config.h>
|
||||||
|
|
||||||
#include <cutils/logger.h>
|
#include <log/logger.h>
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
#include <backtrace/backtrace.h>
|
#include <backtrace/backtrace.h>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <cutils/logd.h>
|
#include <log/logd.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
|
||||||
|
|
@ -264,21 +264,7 @@ void generate_ext4_image(struct image_data *image)
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
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());
|
fd = fileno(tmpfile());
|
||||||
#endif
|
|
||||||
make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
|
make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
|
||||||
|
|
||||||
fstat(fd, &st);
|
fstat(fd, &st);
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <bootimg.h>
|
#include <bootimg.h>
|
||||||
#include <sparse/sparse.h>
|
#include <sparse/sparse.h>
|
||||||
|
|
@ -53,6 +54,8 @@
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
|
||||||
|
|
||||||
char cur_product[FB_RESPONSE_SZ + 1];
|
char cur_product[FB_RESPONSE_SZ + 1];
|
||||||
|
|
||||||
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
|
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
|
||||||
|
|
@ -80,6 +83,27 @@ unsigned ramdisk_offset = 0x01000000;
|
||||||
unsigned second_offset = 0x00f00000;
|
unsigned second_offset = 0x00f00000;
|
||||||
unsigned tags_offset = 0x00000100;
|
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);
|
void get_my_path(char *path);
|
||||||
|
|
||||||
|
|
@ -123,44 +147,28 @@ char *find_item(const char *item, const char *product)
|
||||||
return strdup(path);
|
return strdup(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
static int64_t file_size(int fd)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
off64_t off;
|
struct stat st;
|
||||||
int fd;
|
int ret;
|
||||||
|
|
||||||
fd = open(fn, O_RDONLY);
|
ret = fstat(fd, &st);
|
||||||
if (fd < 0) return -1;
|
|
||||||
|
|
||||||
off = lseek64(fd, 0, SEEK_END);
|
return ret ? -1 : st.st_size;
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *load_file(const char *fn, unsigned *_sz)
|
static void *load_fd(int fd, unsigned *_sz)
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
int sz;
|
int sz;
|
||||||
int fd;
|
|
||||||
int errno_tmp;
|
int errno_tmp;
|
||||||
|
|
||||||
data = 0;
|
data = 0;
|
||||||
fd = open(fn, O_RDONLY);
|
|
||||||
if(fd < 0) return 0;
|
|
||||||
|
|
||||||
sz = lseek(fd, 0, SEEK_END);
|
sz = file_size(fd);
|
||||||
if(sz < 0) goto oops;
|
if (sz < 0) {
|
||||||
|
goto oops;
|
||||||
if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
|
}
|
||||||
|
|
||||||
data = (char*) malloc(sz);
|
data = (char*) malloc(sz);
|
||||||
if(data == 0) goto oops;
|
if(data == 0) goto oops;
|
||||||
|
|
@ -178,7 +186,16 @@ oops:
|
||||||
errno = errno_tmp;
|
errno = errno_tmp;
|
||||||
return 0;
|
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)
|
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;
|
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)
|
static char *strip(char *s)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
@ -489,27 +531,20 @@ void queue_info_dump(void)
|
||||||
fb_queue_notice("--------------------------------------------");
|
fb_queue_notice("--------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sparse_file **load_sparse_files(int fd, int max_size)
|
||||||
struct sparse_file **load_sparse_files(const char *fname, int max_size)
|
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
struct sparse_file *s;
|
struct sparse_file *s;
|
||||||
int files;
|
int files;
|
||||||
struct sparse_file **out_s;
|
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);
|
s = sparse_file_import_auto(fd, false);
|
||||||
if (!s) {
|
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);
|
files = sparse_file_resparse(s, max_size, NULL, 0);
|
||||||
if (files < 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);
|
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);
|
files = sparse_file_resparse(s, max_size, out_s, files);
|
||||||
if (files < 0) {
|
if (files < 0) {
|
||||||
die("Failed to resparse '%s'\n", fname);
|
die("Failed to resparse\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return out_s;
|
return out_s;
|
||||||
|
|
@ -580,29 +615,78 @@ static int needs_erase(const char *part)
|
||||||
return fb_format_supported(usb, 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;
|
int64_t sz64;
|
||||||
void *data;
|
void *data;
|
||||||
int64_t limit;
|
int64_t limit;
|
||||||
|
|
||||||
sz64 = file_size(fname);
|
sz64 = file_size(fd);
|
||||||
|
if (sz64 < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
limit = get_sparse_limit(usb, sz64);
|
limit = get_sparse_limit(usb, sz64);
|
||||||
if (limit) {
|
if (limit) {
|
||||||
struct sparse_file **s = load_sparse_files(fname, limit);
|
struct sparse_file **s = load_sparse_files(fd, limit);
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
die("cannot sparse load '%s'\n", fname);
|
return -1;
|
||||||
}
|
|
||||||
while (*s) {
|
|
||||||
sz64 = sparse_file_len(*s, true, false);
|
|
||||||
fb_queue_flash_sparse(pname, *s++, sz64);
|
|
||||||
}
|
}
|
||||||
|
buf->type = FB_BUFFER_SPARSE;
|
||||||
|
buf->data = s;
|
||||||
} else {
|
} else {
|
||||||
unsigned int sz;
|
unsigned int sz;
|
||||||
data = load_file(fname, &sz);
|
data = load_fd(fd, &sz);
|
||||||
if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno));
|
if (data == 0) return -1;
|
||||||
fb_queue_flash(pname, data, sz);
|
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)
|
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");
|
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;
|
void *zdata;
|
||||||
unsigned zsize;
|
unsigned zsize;
|
||||||
void *data;
|
void *data;
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
zipfile_t zip;
|
zipfile_t zip;
|
||||||
|
int fd;
|
||||||
|
int rc;
|
||||||
|
struct fastboot_buffer buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
queue_info_dump();
|
queue_info_dump();
|
||||||
|
|
||||||
|
|
@ -650,30 +738,25 @@ void do_update(char *fn, int erase_first)
|
||||||
|
|
||||||
setup_requirements(data, sz);
|
setup_requirements(data, sz);
|
||||||
|
|
||||||
data = unzip_file(zip, "boot.img", &sz);
|
for (i = 0; i < ARRAY_SIZE(images); i++) {
|
||||||
if (data == 0) die("update package missing boot.img");
|
fd = unzip_to_file(zip, images[i].img_name);
|
||||||
do_update_signature(zip, "boot.sig");
|
if (fd < 0) {
|
||||||
if (erase_first && needs_erase("boot")) {
|
if (images[i].is_optional)
|
||||||
fb_queue_erase("boot");
|
continue;
|
||||||
}
|
die("update package missing %s", images[i].img_name);
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
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)
|
void do_send_signature(char *fn)
|
||||||
|
|
@ -694,11 +777,13 @@ void do_send_signature(char *fn)
|
||||||
fb_queue_command("signature", "installing signature");
|
fb_queue_command("signature", "installing signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_flashall(int erase_first)
|
void do_flashall(usb_handle *usb, int erase_first)
|
||||||
{
|
{
|
||||||
char *fname;
|
char *fname;
|
||||||
void *data;
|
void *data;
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
|
struct fastboot_buffer buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
queue_info_dump();
|
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));
|
if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
|
||||||
setup_requirements(data, sz);
|
setup_requirements(data, sz);
|
||||||
|
|
||||||
fname = find_item("boot", product);
|
for (i = 0; i < ARRAY_SIZE(images); i++) {
|
||||||
data = load_file(fname, &sz);
|
fname = find_item(images[i].part_name, product);
|
||||||
if (data == 0) die("could not load boot.img: %s", strerror(errno));
|
if (load_buf(usb, fname, &buf)) {
|
||||||
do_send_signature(fname);
|
if (images[i].is_optional)
|
||||||
if (erase_first && needs_erase("boot")) {
|
continue;
|
||||||
fb_queue_erase("boot");
|
die("could not load %s\n", images[i].img_name);
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
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)
|
#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);
|
fb_queue_flash(pname, data, sz);
|
||||||
} else if(!strcmp(*argv, "flashall")) {
|
} else if(!strcmp(*argv, "flashall")) {
|
||||||
skip(1);
|
skip(1);
|
||||||
do_flashall(erase_first);
|
do_flashall(usb, erase_first);
|
||||||
wants_reboot = 1;
|
wants_reboot = 1;
|
||||||
} else if(!strcmp(*argv, "update")) {
|
} else if(!strcmp(*argv, "update")) {
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
do_update(argv[1], erase_first);
|
do_update(usb, argv[1], erase_first);
|
||||||
skip(2);
|
skip(2);
|
||||||
} else {
|
} else {
|
||||||
do_update("update.zip", erase_first);
|
do_update(usb, "update.zip", erase_first);
|
||||||
skip(1);
|
skip(1);
|
||||||
}
|
}
|
||||||
wants_reboot = 1;
|
wants_reboot = 1;
|
||||||
|
|
|
||||||
|
|
@ -36,29 +36,6 @@
|
||||||
|
|
||||||
#include <windows.h>
|
#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])
|
void get_my_path(char exe[PATH_MAX])
|
||||||
{
|
{
|
||||||
char* r;
|
char* r;
|
||||||
|
|
@ -70,47 +47,3 @@ void get_my_path(char exe[PATH_MAX])
|
||||||
*r = 0;
|
*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
38
fastbootd/Android.mk
Normal 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
97
fastbootd/bootimg.h
Normal 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
206
fastbootd/commands.c
Normal 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
161
fastbootd/config.c
Normal 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
42
fastbootd/debug.h
Normal 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
45
fastbootd/fastbootd.c
Normal 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
195
fastbootd/protocol.c
Normal 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
61
fastbootd/protocol.h
Normal 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
149
fastbootd/transport.c
Normal 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
41
fastbootd/transport.h
Normal 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
|
||||||
353
fastbootd/usb_linux_client.c
Normal file
353
fastbootd/usb_linux_client.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -3,12 +3,13 @@
|
||||||
LOCAL_PATH:= $(call my-dir)
|
LOCAL_PATH:= $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
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_C_INCLUDES := $(LOCAL_PATH)/include
|
||||||
|
|
||||||
LOCAL_MODULE:= libfs_mgr
|
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
|
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||||
|
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
@ -28,7 +29,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
|
||||||
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
|
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
|
||||||
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
|
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)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
|
|
||||||
253
fs_mgr/fs_mgr.c
253
fs_mgr/fs_mgr.c
|
|
@ -27,18 +27,35 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <time.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 <private/android_filesystem_config.h>
|
||||||
#include <cutils/partition_utils.h>
|
#include <cutils/partition_utils.h>
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
#include <logwrap/logwrap.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.h"
|
||||||
|
#include "fs_mgr_priv_verity.h"
|
||||||
|
|
||||||
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
|
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
|
||||||
#define KEY_IN_FOOTER "footer"
|
#define KEY_IN_FOOTER "footer"
|
||||||
|
|
||||||
#define E2FSCK_BIN "/system/bin/e2fsck"
|
#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)))
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||||
|
|
||||||
|
|
@ -74,10 +91,23 @@ static struct flag_list fs_mgr_flags[] = {
|
||||||
{ "voldmanaged=",MF_VOLDMANAGED},
|
{ "voldmanaged=",MF_VOLDMANAGED},
|
||||||
{ "length=", MF_LENGTH },
|
{ "length=", MF_LENGTH },
|
||||||
{ "recoveryonly",MF_RECOVERYONLY },
|
{ "recoveryonly",MF_RECOVERYONLY },
|
||||||
|
{ "swapprio=", MF_SWAPPRIO },
|
||||||
|
{ "zramsize=", MF_ZRAMSIZE },
|
||||||
|
{ "verify", MF_VERIFY },
|
||||||
|
{ "noemulatedsd", MF_NOEMULATEDSD },
|
||||||
{ "defaults", 0 },
|
{ "defaults", 0 },
|
||||||
{ 0, 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
|
* gettime() - returns the time in seconds of the system's monotonic clock or
|
||||||
* zero on error.
|
* 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,
|
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)
|
char *fs_options, int fs_options_len)
|
||||||
{
|
{
|
||||||
int f = 0;
|
int f = 0;
|
||||||
|
|
@ -117,21 +147,12 @@ static int parse_flags(char *flags, struct flag_list *fl,
|
||||||
char *p;
|
char *p;
|
||||||
char *savep;
|
char *savep;
|
||||||
|
|
||||||
/* initialize key_loc to null, if we find an MF_CRYPT flag,
|
/* initialize flag values. If we find a relevant flag, we'll
|
||||||
* then we'll set key_loc to the proper value */
|
* update the value */
|
||||||
if (key_loc) {
|
if (flag_vals) {
|
||||||
*key_loc = NULL;
|
memset(flag_vals, 0, sizeof(*flag_vals));
|
||||||
}
|
flag_vals->partnum = -1;
|
||||||
/* initialize part_length to 0, if we find an MF_LENGTH flag,
|
flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
|
||||||
* 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 fs_options to the null string */
|
/* 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++) {
|
for (i = 0; fl[i].name; i++) {
|
||||||
if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
|
if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
|
||||||
f |= fl[i].flag;
|
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
|
/* The encryptable flag is followed by an = and the
|
||||||
* location of the keys. Get it and return it.
|
* location of the keys. Get it and return it.
|
||||||
*/
|
*/
|
||||||
*key_loc = strdup(strchr(p, '=') + 1);
|
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
|
||||||
} else if ((fl[i].flag == MF_LENGTH) && part_length) {
|
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
|
||||||
/* The length flag is followed by an = and the
|
/* The length flag is followed by an = and the
|
||||||
* size of the partition. Get it and return it.
|
* size of the partition. Get it and return it.
|
||||||
*/
|
*/
|
||||||
*part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
|
flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
|
||||||
} else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
|
} else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
|
||||||
/* The voldmanaged flag is followed by an = and the
|
/* The voldmanaged flag is followed by an = and the
|
||||||
* label, a colon and the partition number or the
|
* label, a colon and the partition number or the
|
||||||
* word "auto", e.g.
|
* word "auto", e.g.
|
||||||
|
|
@ -171,17 +192,21 @@ static int parse_flags(char *flags, struct flag_list *fl,
|
||||||
label_start = strchr(p, '=') + 1;
|
label_start = strchr(p, '=') + 1;
|
||||||
label_end = strchr(p, ':');
|
label_end = strchr(p, ':');
|
||||||
if (label_end) {
|
if (label_end) {
|
||||||
*label = strndup(label_start,
|
flag_vals->label = strndup(label_start,
|
||||||
(int) (label_end - label_start));
|
(int) (label_end - label_start));
|
||||||
part_start = strchr(p, ':') + 1;
|
part_start = strchr(p, ':') + 1;
|
||||||
if (!strcmp(part_start, "auto")) {
|
if (!strcmp(part_start, "auto")) {
|
||||||
*partnum = -1;
|
flag_vals->partnum = -1;
|
||||||
} else {
|
} else {
|
||||||
*partnum = strtol(part_start, NULL, 0);
|
flag_vals->partnum = strtol(part_start, NULL, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ERROR("Warning: voldmanaged= flag malformed\n");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -224,10 +249,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
|
||||||
char *save_ptr, *p;
|
char *save_ptr, *p;
|
||||||
struct fstab *fstab = NULL;
|
struct fstab *fstab = NULL;
|
||||||
struct fstab_rec *recs;
|
struct fstab_rec *recs;
|
||||||
char *key_loc;
|
struct fs_mgr_flag_values flag_vals;
|
||||||
long long part_length;
|
|
||||||
char *label;
|
|
||||||
int partnum;
|
|
||||||
#define FS_OPTIONS_LEN 1024
|
#define FS_OPTIONS_LEN 1024
|
||||||
char tmp_fs_options[FS_OPTIONS_LEN];
|
char tmp_fs_options[FS_OPTIONS_LEN];
|
||||||
|
|
||||||
|
|
@ -315,8 +337,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
tmp_fs_options[0] = '\0';
|
tmp_fs_options[0] = '\0';
|
||||||
fstab->recs[cnt].flags = parse_flags(p, mount_flags,
|
fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
|
||||||
NULL, NULL, NULL, NULL,
|
|
||||||
tmp_fs_options, FS_OPTIONS_LEN);
|
tmp_fs_options, FS_OPTIONS_LEN);
|
||||||
|
|
||||||
/* fs_options are optional */
|
/* fs_options are optional */
|
||||||
|
|
@ -331,13 +352,13 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
|
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
|
||||||
&key_loc, &part_length,
|
&flag_vals, NULL, 0);
|
||||||
&label, &partnum,
|
fstab->recs[cnt].key_loc = flag_vals.key_loc;
|
||||||
NULL, 0);
|
fstab->recs[cnt].length = flag_vals.part_length;
|
||||||
fstab->recs[cnt].key_loc = key_loc;
|
fstab->recs[cnt].label = flag_vals.label;
|
||||||
fstab->recs[cnt].length = part_length;
|
fstab->recs[cnt].partnum = flag_vals.partnum;
|
||||||
fstab->recs[cnt].label = label;
|
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
|
||||||
fstab->recs[cnt].partnum = partnum;
|
fstab->recs[cnt].zram_size = flag_vals.zram_size;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
fclose(fstab_file);
|
fclose(fstab_file);
|
||||||
|
|
@ -356,6 +377,10 @@ void fs_mgr_free_fstab(struct fstab *fstab)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!fstab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < fstab->num_entries; i++) {
|
for (i = 0; i < fstab->num_entries; i++) {
|
||||||
/* Free the pointers return by strdup(3) */
|
/* Free the pointers return by strdup(3) */
|
||||||
free(fstab->recs[i].blk_device);
|
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);
|
INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
|
||||||
|
|
||||||
ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
|
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) {
|
if (ret < 0) {
|
||||||
/* No need to check for error in fork, we can't really handle it now */
|
/* 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)
|
static int fs_match(char *in1, char *in2)
|
||||||
{
|
{
|
||||||
char *n1;
|
char *n1;
|
||||||
|
|
@ -470,8 +533,9 @@ int fs_mgr_mount_all(struct fstab *fstab)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip raw partition entries such as boot, recovery, etc */
|
/* Skip swap and raw partition entries such as boot, recovery, etc */
|
||||||
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
|
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
|
||||||
|
!strcmp(fstab->recs[i].fs_type, "emmc") ||
|
||||||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
|
!strcmp(fstab->recs[i].fs_type, "mtd")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -485,9 +549,17 @@ int fs_mgr_mount_all(struct fstab *fstab)
|
||||||
fstab->recs[i].mount_point);
|
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_type, fstab->recs[i].flags,
|
||||||
fstab->recs[i].fs_options);
|
fstab->recs[i].fs_options);
|
||||||
|
|
||||||
if (!mret) {
|
if (!mret) {
|
||||||
/* Success! Go get the next one */
|
/* Success! Go get the next one */
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -543,8 +615,9 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We found our match */
|
/* We found our match */
|
||||||
/* If this is a raw partition, report an error */
|
/* If this swap or a raw partition, report an error */
|
||||||
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
|
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
|
||||||
|
!strcmp(fstab->recs[i].fs_type, "emmc") ||
|
||||||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
|
!strcmp(fstab->recs[i].fs_type, "mtd")) {
|
||||||
ERROR("Cannot mount filesystem of type %s on %s\n",
|
ERROR("Cannot mount filesystem of type %s on %s\n",
|
||||||
fstab->recs[i].fs_type, n_blk_device);
|
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);
|
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 */
|
/* Now mount it where requested */
|
||||||
if (tmp_mount_point) {
|
if (tmp_mount_point) {
|
||||||
m = tmp_mount_point;
|
m = tmp_mount_point;
|
||||||
} else {
|
} else {
|
||||||
m = fstab->recs[i].mount_point;
|
m = fstab->recs[i].mount_point;
|
||||||
}
|
}
|
||||||
if (mount(n_blk_device, m, fstab->recs[i].fs_type,
|
if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
|
||||||
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
|
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
|
||||||
ERROR("Cannot mount filesystem on %s at %s\n",
|
ERROR("Cannot mount filesystem on %s at %s\n",
|
||||||
n_blk_device, m);
|
n_blk_device, m);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -623,6 +703,83 @@ int fs_mgr_unmount_all(struct fstab *fstab)
|
||||||
|
|
||||||
return ret;
|
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
|
* 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;
|
return fstab->fs_mgr_flags & MF_CRYPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
|
||||||
|
{
|
||||||
|
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,17 @@
|
||||||
#define MF_VOLDMANAGED 0x10
|
#define MF_VOLDMANAGED 0x10
|
||||||
#define MF_LENGTH 0x20
|
#define MF_LENGTH 0x20
|
||||||
#define MF_RECOVERYONLY 0x40
|
#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 */
|
#endif /* __CORE_FS_MGR_PRIV_H */
|
||||||
|
|
||||||
|
|
|
||||||
17
fs_mgr/fs_mgr_priv_verity.h
Normal file
17
fs_mgr/fs_mgr_priv_verity.h
Normal 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
410
fs_mgr/fs_mgr_verity.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
#ifndef __CORE_FS_MGR_H
|
#ifndef __CORE_FS_MGR_H
|
||||||
#define __CORE_FS_MGR_H
|
#define __CORE_FS_MGR_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <linux/dm-ioctl.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -35,9 +38,12 @@ struct fstab_rec {
|
||||||
char *fs_options;
|
char *fs_options;
|
||||||
int fs_mgr_flags;
|
int fs_mgr_flags;
|
||||||
char *key_loc;
|
char *key_loc;
|
||||||
|
char *verity_loc;
|
||||||
long long length;
|
long long length;
|
||||||
char *label;
|
char *label;
|
||||||
int partnum;
|
int partnum;
|
||||||
|
int swap_prio;
|
||||||
|
unsigned int zram_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
|
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_voldmanaged(struct fstab_rec *fstab);
|
||||||
int fs_mgr_is_nonremovable(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_encryptable(struct fstab_rec *fstab);
|
||||||
|
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
|
||||||
|
int fs_mgr_swapon_all(struct fstab *fstab);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
30
healthd/Android.mk
Normal file
30
healthd/Android.mk
Normal 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
424
healthd/BatteryMonitor.cpp
Normal 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
61
healthd/BatteryMonitor.h
Normal 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
|
||||||
81
healthd/BatteryPropertiesRegistrar.cpp
Normal file
81
healthd/BatteryPropertiesRegistrar.cpp
Normal 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
|
||||||
52
healthd/BatteryPropertiesRegistrar.h
Normal file
52
healthd/BatteryPropertiesRegistrar.h
Normal 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
285
healthd/healthd.cpp
Normal 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
92
healthd/healthd.h
Normal 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_ */
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,18 +14,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CUTILS_ZYGOTE_H
|
#include <healthd.h>
|
||||||
#define __CUTILS_ZYGOTE_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
void healthd_board_init(struct healthd_config *config)
|
||||||
extern "C" {
|
{
|
||||||
#endif
|
// use defaults
|
||||||
|
|
||||||
int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
|
|
||||||
int zygote_run(int argc, const char **argv);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
}
|
||||||
#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;
|
||||||
|
}
|
||||||
|
|
@ -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__
|
|
||||||
|
|
@ -24,9 +24,8 @@ __BEGIN_DECLS
|
||||||
#define ANDROID_RB_POWEROFF 0xDEAD0002
|
#define ANDROID_RB_POWEROFF 0xDEAD0002
|
||||||
#define ANDROID_RB_RESTART2 0xDEAD0003
|
#define ANDROID_RB_RESTART2 0xDEAD0003
|
||||||
|
|
||||||
/* Flags */
|
/* Properties */
|
||||||
#define ANDROID_RB_FLAG_NO_SYNC 0x1
|
#define ANDROID_RB_PROPERTY "sys.powerctl"
|
||||||
#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
|
|
||||||
|
|
||||||
int android_reboot(int cmd, int flags, char *arg);
|
int android_reboot(int cmd, int flags, char *arg);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -75,6 +75,16 @@ static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
|
||||||
return -1;
|
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)
|
static inline void bitmask_set(unsigned int *bitmask, int bit)
|
||||||
{
|
{
|
||||||
bitmask[BIT_WORD(bit)] |= BIT_MASK(bit);
|
bitmask[BIT_WORD(bit)] |= BIT_MASK(bit);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,563 +1 @@
|
||||||
/*
|
#include <log/log.h>
|
||||||
* 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
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
#ifndef __CUTILS_PROPERTIES_H
|
#ifndef __CUTILS_PROPERTIES_H
|
||||||
#define __CUTILS_PROPERTIES_H
|
#define __CUTILS_PROPERTIES_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/system_properties.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -28,8 +32,8 @@ extern "C" {
|
||||||
** WARNING: system/bionic/include/sys/system_properties.h also defines
|
** WARNING: system/bionic/include/sys/system_properties.h also defines
|
||||||
** these, but with different names. (TODO: fix that)
|
** these, but with different names. (TODO: fix that)
|
||||||
*/
|
*/
|
||||||
#define PROPERTY_KEY_MAX 32
|
#define PROPERTY_KEY_MAX PROP_NAME_MAX
|
||||||
#define PROPERTY_VALUE_MAX 92
|
#define PROPERTY_VALUE_MAX PROP_VALUE_MAX
|
||||||
|
|
||||||
/* property_get: returns the length of the value which will never be
|
/* property_get: returns the length of the value which will never be
|
||||||
** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
|
** 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);
|
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
|
#ifdef HAVE_SYSTEM_PROPERTY_SERVER
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -66,7 +66,8 @@ __BEGIN_DECLS
|
||||||
#define ATRACE_TAG_APP (1<<12)
|
#define ATRACE_TAG_APP (1<<12)
|
||||||
#define ATRACE_TAG_RESOURCES (1<<13)
|
#define ATRACE_TAG_RESOURCES (1<<13)
|
||||||
#define ATRACE_TAG_DALVIK (1<<14)
|
#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.
|
// Reserved for initialization.
|
||||||
#define ATRACE_TAG_NOT_READY (1LL<<63)
|
#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
|
#else // not HAVE_ANDROID_OS
|
||||||
|
|
||||||
#define ATRACE_INIT()
|
#define ATRACE_INIT()
|
||||||
#define ATRACE_GET_ENABLED_TAGS()
|
#define ATRACE_GET_ENABLED_TAGS()
|
||||||
#define ATRACE_ENABLED()
|
#define ATRACE_ENABLED() 0
|
||||||
#define ATRACE_BEGIN(name)
|
#define ATRACE_BEGIN(name)
|
||||||
#define ATRACE_END()
|
#define ATRACE_END()
|
||||||
#define ATRACE_ASYNC_BEGIN(name, cookie)
|
#define ATRACE_ASYNC_BEGIN(name, cookie)
|
||||||
|
|
|
||||||
563
include/log/log.h
Normal file
563
include/log/log.h
Normal 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
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
#ifdef HAVE_PTHREADS
|
#ifdef HAVE_PTHREADS
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
#include <cutils/uio.h>
|
#include <log/uio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
#ifndef _LOGPRINT_H
|
#ifndef _LOGPRINT_H
|
||||||
#define _LOGPRINT_H
|
#define _LOGPRINT_H
|
||||||
|
|
||||||
#include <cutils/log.h>
|
#include <log/log.h>
|
||||||
#include <cutils/logger.h>
|
#include <log/logger.h>
|
||||||
#include <cutils/event_tag_map.h>
|
#include <log/event_tag_map.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
147
include/memtrack/memtrack.h
Normal file
147
include/memtrack/memtrack.h
Normal 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
|
||||||
|
|
@ -30,7 +30,9 @@ extern int dhcp_do_request(const char *ifname,
|
||||||
char *dns[],
|
char *dns[],
|
||||||
char *server,
|
char *server,
|
||||||
uint32_t *lease,
|
uint32_t *lease,
|
||||||
char *vendorInfo);
|
char *vendorInfo,
|
||||||
|
char *domain,
|
||||||
|
char *mtu);
|
||||||
extern int dhcp_do_request_renew(const char *ifname,
|
extern int dhcp_do_request_renew(const char *ifname,
|
||||||
char *ipaddr,
|
char *ipaddr,
|
||||||
char *gateway,
|
char *gateway,
|
||||||
|
|
@ -38,7 +40,9 @@ extern int dhcp_do_request_renew(const char *ifname,
|
||||||
char *dns[],
|
char *dns[],
|
||||||
char *server,
|
char *server,
|
||||||
uint32_t *lease,
|
uint32_t *lease,
|
||||||
char *vendorInfo);
|
char *vendorInfo,
|
||||||
|
char *domain,
|
||||||
|
char *mtu);
|
||||||
extern int dhcp_stop(const char *ifname);
|
extern int dhcp_stop(const char *ifname);
|
||||||
extern int dhcp_release_lease(const char *ifname);
|
extern int dhcp_release_lease(const char *ifname);
|
||||||
extern char *dhcp_get_errmsg();
|
extern char *dhcp_get_errmsg();
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This is the master Users and Groups config for the platform.
|
/* 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 */
|
#define AID_ROOT 0 /* traditional unix root user */
|
||||||
|
|
||||||
|
|
@ -72,6 +72,10 @@
|
||||||
#define AID_CLAT 1029 /* clat part of nat464 */
|
#define AID_CLAT 1029 /* clat part of nat464 */
|
||||||
#define AID_LOOP_RADIO 1030 /* loop radio devices */
|
#define AID_LOOP_RADIO 1030 /* loop radio devices */
|
||||||
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
|
#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_SHELL 2000 /* adb and debug shell user */
|
||||||
#define AID_CACHE 2001 /* cache access */
|
#define AID_CACHE 2001 /* cache access */
|
||||||
|
|
@ -108,50 +112,61 @@ struct android_id_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct android_id_info android_ids[] = {
|
static const struct android_id_info android_ids[] = {
|
||||||
{ "root", AID_ROOT, },
|
{ "root", AID_ROOT, },
|
||||||
{ "system", AID_SYSTEM, },
|
|
||||||
{ "radio", AID_RADIO, },
|
{ "system", AID_SYSTEM, },
|
||||||
{ "bluetooth", AID_BLUETOOTH, },
|
|
||||||
{ "graphics", AID_GRAPHICS, },
|
{ "radio", AID_RADIO, },
|
||||||
{ "input", AID_INPUT, },
|
{ "bluetooth", AID_BLUETOOTH, },
|
||||||
{ "audio", AID_AUDIO, },
|
{ "graphics", AID_GRAPHICS, },
|
||||||
{ "camera", AID_CAMERA, },
|
{ "input", AID_INPUT, },
|
||||||
{ "log", AID_LOG, },
|
{ "audio", AID_AUDIO, },
|
||||||
{ "compass", AID_COMPASS, },
|
{ "camera", AID_CAMERA, },
|
||||||
{ "mount", AID_MOUNT, },
|
{ "log", AID_LOG, },
|
||||||
{ "wifi", AID_WIFI, },
|
{ "compass", AID_COMPASS, },
|
||||||
{ "dhcp", AID_DHCP, },
|
{ "mount", AID_MOUNT, },
|
||||||
{ "adb", AID_ADB, },
|
{ "wifi", AID_WIFI, },
|
||||||
{ "install", AID_INSTALL, },
|
{ "adb", AID_ADB, },
|
||||||
{ "media", AID_MEDIA, },
|
{ "install", AID_INSTALL, },
|
||||||
{ "drm", AID_DRM, },
|
{ "media", AID_MEDIA, },
|
||||||
{ "mdnsr", AID_MDNSR, },
|
{ "dhcp", AID_DHCP, },
|
||||||
{ "nfc", AID_NFC, },
|
{ "sdcard_rw", AID_SDCARD_RW, },
|
||||||
{ "drmrpc", AID_DRMRPC, },
|
{ "vpn", AID_VPN, },
|
||||||
{ "shell", AID_SHELL, },
|
{ "keystore", AID_KEYSTORE, },
|
||||||
{ "cache", AID_CACHE, },
|
{ "usb", AID_USB, },
|
||||||
{ "diag", AID_DIAG, },
|
{ "drm", AID_DRM, },
|
||||||
{ "net_bt_admin", AID_NET_BT_ADMIN, },
|
{ "mdnsr", AID_MDNSR, },
|
||||||
{ "net_bt", AID_NET_BT, },
|
{ "gps", AID_GPS, },
|
||||||
{ "net_bt_stack", AID_NET_BT_STACK, },
|
// AID_UNUSED1
|
||||||
{ "sdcard_r", AID_SDCARD_R, },
|
{ "media_rw", AID_MEDIA_RW, },
|
||||||
{ "sdcard_rw", AID_SDCARD_RW, },
|
{ "mtp", AID_MTP, },
|
||||||
{ "media_rw", AID_MEDIA_RW, },
|
// AID_UNUSED2
|
||||||
{ "vpn", AID_VPN, },
|
{ "drmrpc", AID_DRMRPC, },
|
||||||
{ "keystore", AID_KEYSTORE, },
|
{ "nfc", AID_NFC, },
|
||||||
{ "usb", AID_USB, },
|
{ "sdcard_r", AID_SDCARD_R, },
|
||||||
{ "mtp", AID_MTP, },
|
{ "clat", AID_CLAT, },
|
||||||
{ "gps", AID_GPS, },
|
{ "loop_radio", AID_LOOP_RADIO, },
|
||||||
{ "inet", AID_INET, },
|
{ "mediadrm", AID_MEDIA_DRM, },
|
||||||
{ "net_raw", AID_NET_RAW, },
|
{ "package_info", AID_PACKAGE_INFO, },
|
||||||
{ "net_admin", AID_NET_ADMIN, },
|
{ "sdcard_pics", AID_SDCARD_PICS, },
|
||||||
{ "net_bw_stats", AID_NET_BW_STATS, },
|
{ "sdcard_av", AID_SDCARD_AV, },
|
||||||
{ "net_bw_acct", AID_NET_BW_ACCT, },
|
{ "sdcard_all", AID_SDCARD_ALL, },
|
||||||
{ "loop_radio", AID_LOOP_RADIO, },
|
|
||||||
{ "misc", AID_MISC, },
|
{ "shell", AID_SHELL, },
|
||||||
{ "nobody", AID_NOBODY, },
|
{ "cache", AID_CACHE, },
|
||||||
{ "clat", AID_CLAT, },
|
{ "diag", AID_DIAG, },
|
||||||
{ "mediadrm", AID_MEDIA_DRM, },
|
|
||||||
|
{ "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 \
|
#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" },
|
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/tcpdump" },
|
||||||
{ 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
|
{ 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" },
|
{ 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
|
||||||
|
|
||||||
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
|
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ __BEGIN_DECLS
|
||||||
* frameworks/base/include/media/AudioSystem.h
|
* 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;
|
typedef int audio_io_handle_t;
|
||||||
|
|
||||||
/* Audio stream types */
|
/* Audio stream types */
|
||||||
|
|
@ -69,6 +72,11 @@ typedef enum {
|
||||||
/* play the mix captured by this audio source. */
|
/* play the mix captured by this audio source. */
|
||||||
AUDIO_SOURCE_CNT,
|
AUDIO_SOURCE_CNT,
|
||||||
AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1,
|
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;
|
} audio_source_t;
|
||||||
|
|
||||||
/* special audio session values
|
/* special audio session values
|
||||||
|
|
@ -383,9 +391,51 @@ typedef enum {
|
||||||
// controls related to voice calls.
|
// controls related to voice calls.
|
||||||
AUDIO_OUTPUT_FLAG_FAST = 0x4, // output supports "fast tracks",
|
AUDIO_OUTPUT_FLAG_FAST = 0x4, // output supports "fast tracks",
|
||||||
// defined elsewhere
|
// 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;
|
} 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)
|
static inline bool audio_is_output_device(audio_devices_t device)
|
||||||
{
|
{
|
||||||
if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
|
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)
|
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;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
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)
|
if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
|
||||||
return true;
|
return channel != 0;
|
||||||
else
|
else
|
||||||
return false;
|
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)
|
if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
|
||||||
return true;
|
return channel != 0;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,40 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum {
|
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_RGBA_8888 = 1,
|
||||||
HAL_PIXEL_FORMAT_RGBX_8888 = 2,
|
HAL_PIXEL_FORMAT_RGBX_8888 = 2,
|
||||||
HAL_PIXEL_FORMAT_RGB_888 = 3,
|
HAL_PIXEL_FORMAT_RGB_888 = 3,
|
||||||
HAL_PIXEL_FORMAT_RGB_565 = 4,
|
HAL_PIXEL_FORMAT_RGB_565 = 4,
|
||||||
HAL_PIXEL_FORMAT_BGRA_8888 = 5,
|
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
|
* 0x100 - 0x1FF
|
||||||
|
|
@ -268,6 +293,8 @@ enum {
|
||||||
HAL_TRANSFORM_ROT_180 = 0x03,
|
HAL_TRANSFORM_ROT_180 = 0x03,
|
||||||
/* rotate source image 270 degrees clockwise */
|
/* rotate source image 270 degrees clockwise */
|
||||||
HAL_TRANSFORM_ROT_270 = 0x07,
|
HAL_TRANSFORM_ROT_270 = 0x07,
|
||||||
|
/* don't use. see system/window.h */
|
||||||
|
HAL_TRANSFORM_RESERVED = 0x08,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
77
include/system/thread_defs.h
Normal file
77
include/system/thread_defs.h
Normal 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 */
|
||||||
|
|
@ -230,7 +230,13 @@ enum {
|
||||||
* Boolean that indicates whether the consumer is running more than
|
* Boolean that indicates whether the consumer is running more than
|
||||||
* one buffer behind the producer.
|
* 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.
|
/* Valid operations for the (*perform)() hook.
|
||||||
|
|
@ -290,12 +296,15 @@ enum {
|
||||||
NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
|
NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
|
||||||
/* flip source image vertically */
|
/* flip source image vertically */
|
||||||
NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
|
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,
|
NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
|
||||||
/* rotate source image 180 degrees */
|
/* rotate source image 180 degrees */
|
||||||
NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
|
NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
|
||||||
/* rotate source image 270 degrees clock-wise */
|
/* rotate source image 270 degrees clock-wise */
|
||||||
NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
|
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 */
|
/* parameter for NATIVE_WINDOW_SET_SCALING_MODE */
|
||||||
|
|
|
||||||
128
include/utils/AndroidThreads.h
Normal file
128
include/utils/AndroidThreads.h
Normal 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
22
include/utils/Atomic.h
Normal 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
|
||||||
402
include/utils/BasicHashtable.h
Normal file
402
include/utils/BasicHashtable.h
Normal 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
124
include/utils/BitSet.h
Normal 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
243
include/utils/BlobCache.h
Normal 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
81
include/utils/ByteOrder.h
Normal 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
76
include/utils/CallStack.h
Normal 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
65
include/utils/Compat.h
Normal 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
147
include/utils/Condition.h
Normal 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
48
include/utils/Debug.h
Normal 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
40
include/utils/Endian.h
Normal 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
88
include/utils/Errors.h
Normal 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
136
include/utils/FileMap.h
Normal 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
198
include/utils/Flattenable.h
Normal 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
33
include/utils/Functor.h
Normal 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
|
||||||
48
include/utils/JenkinsHash.h
Normal file
48
include/utils/JenkinsHash.h
Normal 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
224
include/utils/KeyedVector.h
Normal 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
|
||||||
97
include/utils/LinearAllocator.h
Normal file
97
include/utils/LinearAllocator.h
Normal 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
|
||||||
64
include/utils/LinearTransform.h
Normal file
64
include/utils/LinearTransform.h
Normal 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
332
include/utils/List.h
Normal 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
71
include/utils/Log.h
Normal 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
388
include/utils/Looper.h
Normal 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
237
include/utils/LruCache.h
Normal 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
137
include/utils/Mutex.h
Normal 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
106
include/utils/PropertyMap.h
Normal 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
126
include/utils/RWLock.h
Normal 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
546
include/utils/RefBase.h
Normal 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
|
||||||
137
include/utils/SharedBuffer.h
Normal file
137
include/utils/SharedBuffer.h
Normal 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
77
include/utils/Singleton.h
Normal 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
Loading…
Add table
Reference in a new issue