auto import from //depot/cupcake/@135843
This commit is contained in:
parent
cf59fa8dc7
commit
cbb1011c95
117 changed files with 34252 additions and 0 deletions
0
MODULE_LICENSE_APACHE2
Normal file
0
MODULE_LICENSE_APACHE2
Normal file
222
NOTICE
Normal file
222
NOTICE
Normal file
|
@ -0,0 +1,222 @@
|
|||
=========================================================================
|
||||
== 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-2004 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.
|
||||
|
||||
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
|
||||
|
33
include/utils.h
Normal file
33
include/utils.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Handy utility functions and portability code. This file includes all
|
||||
// of the generally-useful headers in the "utils" directory.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_H
|
||||
#define _LIBS_UTILS_H
|
||||
|
||||
#include <utils/ported.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/string_array.h>
|
||||
#include <utils/misc.h>
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#endif // _LIBS_UTILS_H
|
255
include/utils/AndroidUnicode.h
Normal file
255
include/utils/AndroidUnicode.h
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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 ANDROID_UNICODE_H
|
||||
#define ANDROID_UNICODE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define REPLACEMENT_CHAR (0xFFFD)
|
||||
|
||||
// this part of code is copied from umachine.h under ICU
|
||||
/**
|
||||
* Define UChar32 as a type for single Unicode code points.
|
||||
* UChar32 is a signed 32-bit integer (same as int32_t).
|
||||
*
|
||||
* The Unicode code point range is 0..0x10ffff.
|
||||
* All other values (negative or >=0x110000) are illegal as Unicode code points.
|
||||
* They may be used as sentinel values to indicate "done", "error"
|
||||
* or similar non-code point conditions.
|
||||
*
|
||||
* @stable ICU 2.4
|
||||
*/
|
||||
typedef int32_t UChar32;
|
||||
|
||||
namespace android {
|
||||
|
||||
class Encoding;
|
||||
/**
|
||||
* \class Unicode
|
||||
*
|
||||
* Helper class for getting properties of Unicode characters. Characters
|
||||
* can have one of the types listed in CharType and each character can have the
|
||||
* directionality of Direction.
|
||||
*/
|
||||
class Unicode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Directions specified in the Unicode standard. These directions map directly
|
||||
* to java.lang.Character.
|
||||
*/
|
||||
enum Direction {
|
||||
DIRECTIONALITY_UNDEFINED = -1,
|
||||
DIRECTIONALITY_LEFT_TO_RIGHT,
|
||||
DIRECTIONALITY_RIGHT_TO_LEFT,
|
||||
DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
|
||||
DIRECTIONALITY_EUROPEAN_NUMBER,
|
||||
DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR,
|
||||
DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR,
|
||||
DIRECTIONALITY_ARABIC_NUMBER,
|
||||
DIRECTIONALITY_COMMON_NUMBER_SEPARATOR,
|
||||
DIRECTIONALITY_NONSPACING_MARK,
|
||||
DIRECTIONALITY_BOUNDARY_NEUTRAL,
|
||||
DIRECTIONALITY_PARAGRAPH_SEPARATOR,
|
||||
DIRECTIONALITY_SEGMENT_SEPARATOR,
|
||||
DIRECTIONALITY_WHITESPACE,
|
||||
DIRECTIONALITY_OTHER_NEUTRALS,
|
||||
DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
|
||||
DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE,
|
||||
DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING,
|
||||
DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE,
|
||||
DIRECTIONALITY_POP_DIRECTIONAL_FORMAT
|
||||
};
|
||||
|
||||
/**
|
||||
* Character types as specified in the Unicode standard. These map directly to
|
||||
* java.lang.Character.
|
||||
*/
|
||||
enum CharType {
|
||||
CHARTYPE_UNASSIGNED = 0,
|
||||
CHARTYPE_UPPERCASE_LETTER,
|
||||
CHARTYPE_LOWERCASE_LETTER,
|
||||
CHARTYPE_TITLECASE_LETTER,
|
||||
CHARTYPE_MODIFIER_LETTER,
|
||||
CHARTYPE_OTHER_LETTER,
|
||||
CHARTYPE_NON_SPACING_MARK,
|
||||
CHARTYPE_ENCLOSING_MARK,
|
||||
CHARTYPE_COMBINING_SPACING_MARK,
|
||||
CHARTYPE_DECIMAL_DIGIT_NUMBER,
|
||||
CHARTYPE_LETTER_NUMBER,
|
||||
CHARTYPE_OTHER_NUMBER,
|
||||
CHARTYPE_SPACE_SEPARATOR,
|
||||
CHARTYPE_LINE_SEPARATOR,
|
||||
CHARTYPE_PARAGRAPH_SEPARATOR,
|
||||
CHARTYPE_CONTROL,
|
||||
CHARTYPE_FORMAT,
|
||||
CHARTYPE_MISSING_VALUE_FOR_JAVA, /* This is the mysterious missing 17 value from the java constants */
|
||||
CHARTYPE_PRIVATE_USE,
|
||||
CHARTYPE_SURROGATE,
|
||||
CHARTYPE_DASH_PUNCTUATION,
|
||||
CHARTYPE_START_PUNCTUATION,
|
||||
CHARTYPE_END_PUNCTUATION,
|
||||
CHARTYPE_CONNECTOR_PUNCTUATION,
|
||||
CHARTYPE_OTHER_PUNCTUATION,
|
||||
CHARTYPE_MATH_SYMBOL,
|
||||
CHARTYPE_CURRENCY_SYMBOL,
|
||||
CHARTYPE_MODIFIER_SYMBOL,
|
||||
CHARTYPE_OTHER_SYMBOL,
|
||||
CHARTYPE_INITIAL_QUOTE_PUNCTUATION,
|
||||
CHARTYPE_FINAL_QUOTE_PUNCTUATION
|
||||
};
|
||||
|
||||
/**
|
||||
* Decomposition types as described by the unicode standard. These values map to
|
||||
* the same values in uchar.h in ICU.
|
||||
*/
|
||||
enum DecompositionType {
|
||||
DECOMPOSITION_NONE = 0,
|
||||
DECOMPOSITION_CANONICAL,
|
||||
DECOMPOSITION_COMPAT,
|
||||
DECOMPOSITION_CIRCLE,
|
||||
DECOMPOSITION_FINAL,
|
||||
DECOMPOSITION_FONT,
|
||||
DECOMPOSITION_FRACTION,
|
||||
DECOMPOSITION_INITIAL,
|
||||
DECOMPOSITION_ISOLATED,
|
||||
DECOMPOSITION_MEDIAL,
|
||||
DECOMPOSITION_NARROW,
|
||||
DECOMPOSITION_NOBREAK,
|
||||
DECOMPOSITION_SMALL,
|
||||
DECOMPOSITION_SQUARE,
|
||||
DECOMPOSITION_SUB,
|
||||
DECOMPOSITION_SUPER,
|
||||
DECOMPOSITION_VERTICAL,
|
||||
DECOMPOSITION_WIDE
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the packed data for java calls
|
||||
* @param c The unicode character.
|
||||
* @return The packed data for the character.
|
||||
*
|
||||
* Copied from java.lang.Character implementation:
|
||||
* 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
|
||||
* F E D C B A 9 8 7 6 5 4 3 2 1 0 F E D C B A 9 8 7 6 5 4 3 2 1 0
|
||||
*
|
||||
* 31 types ---------
|
||||
* 18 directionalities ---------
|
||||
* 2 mirroreds -
|
||||
* ----------- 56 toupper diffs
|
||||
* ----------- 48 tolower diffs
|
||||
* --- 4 totitlecase diffs
|
||||
* ------------- 84 numeric values
|
||||
* --------- 24 mirror char diffs
|
||||
*/
|
||||
static uint32_t getPackedData(UChar32 c);
|
||||
|
||||
/**
|
||||
* Get the Character type.
|
||||
* @param c The unicode character.
|
||||
* @return The character's type or CHARTYPE_UNASSIGNED if the character is invalid
|
||||
* or has an unassigned class.
|
||||
*/
|
||||
static CharType getType(UChar32 c);
|
||||
|
||||
/**
|
||||
* Get the Character's decomposition type.
|
||||
* @param c The unicode character.
|
||||
* @return The character's decomposition type or DECOMPOSITION_NONE is there
|
||||
* is no decomposition.
|
||||
*/
|
||||
static DecompositionType getDecompositionType(UChar32 c);
|
||||
|
||||
/**
|
||||
* Returns the digit value of a character or -1 if the character
|
||||
* is not within the specified radix.
|
||||
*
|
||||
* The digit value is computed for integer characters and letters
|
||||
* within the given radix. This function does not handle Roman Numerals,
|
||||
* fractions, or any other characters that may represent numbers.
|
||||
*
|
||||
* @param c The unicode character
|
||||
* @param radix The intended radix.
|
||||
* @return The digit value or -1 if there is no digit value or if the value is outside the radix.
|
||||
*/
|
||||
static int getDigitValue(UChar32 c, int radix = 10);
|
||||
|
||||
/**
|
||||
* Return the numeric value of a character
|
||||
*
|
||||
* @param c The unicode character.
|
||||
* @return The numeric value of the character. -1 if the character has no numeric value,
|
||||
* -2 if the character has a numeric value that is not representable by an integer.
|
||||
*/
|
||||
static int getNumericValue(UChar32 c);
|
||||
|
||||
/**
|
||||
* Convert the character to lowercase
|
||||
* @param c The unicode character.
|
||||
* @return The lowercase character equivalent of c. If c does not have a lowercase equivalent,
|
||||
* the original character is returned.
|
||||
*/
|
||||
static UChar32 toLower(UChar32 c);
|
||||
|
||||
/**
|
||||
* Convert the character to uppercase
|
||||
* @param c The unicode character.
|
||||
* @return The uppercase character equivalent of c. If c does not have an uppercase equivalent,
|
||||
* the original character is returned.
|
||||
*/
|
||||
static UChar32 toUpper(UChar32 c);
|
||||
|
||||
/**
|
||||
* Get the directionality of the character.
|
||||
* @param c The unicode character.
|
||||
* @return The direction of the character or DIRECTIONALITY_UNDEFINED.
|
||||
*/
|
||||
static Direction getDirectionality(UChar32 c);
|
||||
|
||||
/**
|
||||
* Check if the character is a mirrored character. This means that the character
|
||||
* has an equivalent character that is the mirror image of itself.
|
||||
* @param c The unicode character.
|
||||
* @return True iff c has a mirror equivalent.
|
||||
*/
|
||||
static bool isMirrored(UChar32 c);
|
||||
|
||||
/**
|
||||
* Return the mirror of the given character.
|
||||
* @param c The unicode character.
|
||||
* @return The mirror equivalent of c. If c does not have a mirror equivalent,
|
||||
* the original character is returned.
|
||||
* @see isMirrored
|
||||
*/
|
||||
static UChar32 toMirror(UChar32 c);
|
||||
|
||||
/**
|
||||
* Convert the character to title case.
|
||||
* @param c The unicode character.
|
||||
* @return The titlecase equivalent of c. If c does not have a titlecase equivalent,
|
||||
* the original character is returned.
|
||||
*/
|
||||
static UChar32 toTitle(UChar32 c);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
315
include/utils/Asset.h
Normal file
315
include/utils/Asset.h
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Class providing access to a read-only asset. Asset objects are NOT
|
||||
// thread-safe, and should not be shared across threads.
|
||||
//
|
||||
#ifndef __LIBS_ASSET_H
|
||||
#define __LIBS_ASSET_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "FileMap.h"
|
||||
#include "String8.h"
|
||||
#include "Errors.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Instances of this class provide read-only operations on a byte stream.
|
||||
*
|
||||
* Access may be optimized for streaming, random, or whole buffer modes. All
|
||||
* operations are supported regardless of how the file was opened, but some
|
||||
* things will be less efficient. [pass that in??]
|
||||
*
|
||||
* "Asset" is the base class for all types of assets. The classes below
|
||||
* provide most of the implementation. The AssetManager uses one of the
|
||||
* static "create" functions defined here to create a new instance.
|
||||
*/
|
||||
class Asset {
|
||||
public:
|
||||
virtual ~Asset(void);
|
||||
|
||||
static int32_t getGlobalCount();
|
||||
|
||||
/* used when opening an asset */
|
||||
typedef enum AccessMode {
|
||||
ACCESS_UNKNOWN = 0,
|
||||
|
||||
/* read chunks, and seek forward and backward */
|
||||
ACCESS_RANDOM,
|
||||
|
||||
/* read sequentially, with an occasional forward seek */
|
||||
ACCESS_STREAMING,
|
||||
|
||||
/* caller plans to ask for a read-only buffer with all data */
|
||||
ACCESS_BUFFER,
|
||||
} AccessMode;
|
||||
|
||||
enum {
|
||||
/* data larger than this does not get uncompressed into a buffer */
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
UNCOMPRESS_DATA_MAX = 1 * 1024 * 1024
|
||||
#else
|
||||
UNCOMPRESS_DATA_MAX = 2 * 1024 * 1024
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Read data from the current offset. Returns the actual number of
|
||||
* bytes read, 0 on EOF, or -1 on error.
|
||||
*/
|
||||
virtual ssize_t read(void* buf, size_t count) = 0;
|
||||
|
||||
/*
|
||||
* Seek to the specified offset. "whence" uses the same values as
|
||||
* lseek/fseek. Returns the new position on success, or (off_t) -1
|
||||
* on failure.
|
||||
*/
|
||||
virtual off_t seek(off_t offset, int whence) = 0;
|
||||
|
||||
/*
|
||||
* Close the asset, freeing all associated resources.
|
||||
*/
|
||||
virtual void close(void) = 0;
|
||||
|
||||
/*
|
||||
* Get a pointer to a buffer with the entire contents of the file.
|
||||
*/
|
||||
virtual const void* getBuffer(bool wordAligned) = 0;
|
||||
|
||||
/*
|
||||
* Get the total amount of data that can be read.
|
||||
*/
|
||||
virtual off_t getLength(void) const = 0;
|
||||
|
||||
/*
|
||||
* Get the total amount of data that can be read from the current position.
|
||||
*/
|
||||
virtual off_t getRemainingLength(void) const = 0;
|
||||
|
||||
/*
|
||||
* Open a new file descriptor that can be used to read this asset.
|
||||
* Returns -1 if you can not use the file descriptor (for example if the
|
||||
* asset is compressed).
|
||||
*/
|
||||
virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const = 0;
|
||||
|
||||
/*
|
||||
* Get a string identifying the asset's source. This might be a full
|
||||
* path, it might be a colon-separated list of identifiers.
|
||||
*
|
||||
* This is NOT intended to be used for anything except debug output.
|
||||
* DO NOT try to parse this or use it to open a file.
|
||||
*/
|
||||
const char* getAssetSource(void) const { return mAssetSource.string(); }
|
||||
|
||||
protected:
|
||||
Asset(void); // constructor; only invoked indirectly
|
||||
|
||||
/* handle common seek() housekeeping */
|
||||
off_t handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn);
|
||||
|
||||
/* set the asset source string */
|
||||
void setAssetSource(const String8& path) { mAssetSource = path; }
|
||||
|
||||
AccessMode getAccessMode(void) const { return mAccessMode; }
|
||||
|
||||
private:
|
||||
/* these operations are not implemented */
|
||||
Asset(const Asset& src);
|
||||
Asset& operator=(const Asset& src);
|
||||
|
||||
/* AssetManager needs access to our "create" functions */
|
||||
friend class AssetManager;
|
||||
|
||||
/*
|
||||
* Create the asset from a named file on disk.
|
||||
*/
|
||||
static Asset* createFromFile(const char* fileName, AccessMode mode);
|
||||
|
||||
/*
|
||||
* Create the asset from a named, compressed file on disk (e.g. ".gz").
|
||||
*/
|
||||
static Asset* createFromCompressedFile(const char* fileName,
|
||||
AccessMode mode);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Create the asset from a segment of an open file. This will fail
|
||||
* if "offset" and "length" don't fit within the bounds of the file.
|
||||
*
|
||||
* The asset takes ownership of the file descriptor.
|
||||
*/
|
||||
static Asset* createFromFileSegment(int fd, off_t offset, size_t length,
|
||||
AccessMode mode);
|
||||
|
||||
/*
|
||||
* Create from compressed data. "fd" should be seeked to the start of
|
||||
* the compressed data. This could be inside a gzip file or part of a
|
||||
* Zip archive.
|
||||
*
|
||||
* The asset takes ownership of the file descriptor.
|
||||
*
|
||||
* This may not verify the validity of the compressed data until first
|
||||
* use.
|
||||
*/
|
||||
static Asset* createFromCompressedData(int fd, off_t offset,
|
||||
int compressionMethod, size_t compressedLength,
|
||||
size_t uncompressedLength, AccessMode mode);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create the asset from a memory-mapped file segment.
|
||||
*
|
||||
* The asset takes ownership of the FileMap.
|
||||
*/
|
||||
static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
|
||||
|
||||
/*
|
||||
* Create the asset from a memory-mapped file segment with compressed
|
||||
* data. "method" is a Zip archive compression method constant.
|
||||
*
|
||||
* The asset takes ownership of the FileMap.
|
||||
*/
|
||||
static Asset* createFromCompressedMap(FileMap* dataMap, int method,
|
||||
size_t uncompressedLen, AccessMode mode);
|
||||
|
||||
|
||||
/*
|
||||
* Create from a reference-counted chunk of shared memory.
|
||||
*/
|
||||
// TODO
|
||||
|
||||
AccessMode mAccessMode; // how the asset was opened
|
||||
String8 mAssetSource; // debug string
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
*
|
||||
* Innards follow. Do not use these classes directly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* An asset based on an uncompressed file on disk. It may encompass the
|
||||
* entire file or just a piece of it. Access is through fread/fseek.
|
||||
*/
|
||||
class _FileAsset : public Asset {
|
||||
public:
|
||||
_FileAsset(void);
|
||||
virtual ~_FileAsset(void);
|
||||
|
||||
/*
|
||||
* Use a piece of an already-open file.
|
||||
*
|
||||
* On success, the object takes ownership of "fd".
|
||||
*/
|
||||
status_t openChunk(const char* fileName, int fd, off_t offset, size_t length);
|
||||
|
||||
/*
|
||||
* Use a memory-mapped region.
|
||||
*
|
||||
* On success, the object takes ownership of "dataMap".
|
||||
*/
|
||||
status_t openChunk(FileMap* dataMap);
|
||||
|
||||
/*
|
||||
* Standard Asset interfaces.
|
||||
*/
|
||||
virtual ssize_t read(void* buf, size_t count);
|
||||
virtual off_t seek(off_t offset, int whence);
|
||||
virtual void close(void);
|
||||
virtual const void* getBuffer(bool wordAligned);
|
||||
virtual off_t getLength(void) const { return mLength; }
|
||||
virtual off_t getRemainingLength(void) const { return mLength-mOffset; }
|
||||
virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const;
|
||||
|
||||
private:
|
||||
off_t mStart; // absolute file offset of start of chunk
|
||||
off_t mLength; // length of the chunk
|
||||
off_t mOffset; // current local offset, 0 == mStart
|
||||
FILE* mFp; // for read/seek
|
||||
char* mFileName; // for opening
|
||||
|
||||
/*
|
||||
* To support getBuffer() we either need to read the entire thing into
|
||||
* a buffer or memory-map it. For small files it's probably best to
|
||||
* just read them in.
|
||||
*/
|
||||
enum { kReadVsMapThreshold = 4096 };
|
||||
|
||||
FileMap* mMap; // for memory map
|
||||
unsigned char* mBuf; // for read
|
||||
|
||||
const void* ensureAlignment(FileMap* map);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* An asset based on compressed data in a file.
|
||||
*/
|
||||
class _CompressedAsset : public Asset {
|
||||
public:
|
||||
_CompressedAsset(void);
|
||||
virtual ~_CompressedAsset(void);
|
||||
|
||||
/*
|
||||
* Use a piece of an already-open file.
|
||||
*
|
||||
* On success, the object takes ownership of "fd".
|
||||
*/
|
||||
status_t openChunk(int fd, off_t offset, int compressionMethod,
|
||||
size_t uncompressedLen, size_t compressedLen);
|
||||
|
||||
/*
|
||||
* Use a memory-mapped region.
|
||||
*
|
||||
* On success, the object takes ownership of "fd".
|
||||
*/
|
||||
status_t openChunk(FileMap* dataMap, int compressionMethod,
|
||||
size_t uncompressedLen);
|
||||
|
||||
/*
|
||||
* Standard Asset interfaces.
|
||||
*/
|
||||
virtual ssize_t read(void* buf, size_t count);
|
||||
virtual off_t seek(off_t offset, int whence);
|
||||
virtual void close(void);
|
||||
virtual const void* getBuffer(bool wordAligned);
|
||||
virtual off_t getLength(void) const { return mUncompressedLen; }
|
||||
virtual off_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
|
||||
virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const { return -1; }
|
||||
|
||||
private:
|
||||
off_t mStart; // offset to start of compressed data
|
||||
off_t mCompressedLen; // length of the compressed data
|
||||
off_t mUncompressedLen; // length of the uncompressed data
|
||||
off_t mOffset; // current offset, 0 == start of uncomp data
|
||||
|
||||
FileMap* mMap; // for memory-mapped input
|
||||
int mFd; // for file input
|
||||
|
||||
unsigned char* mBuf; // for getBuffer()
|
||||
};
|
||||
|
||||
// need: shared mmap version?
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ASSET_H
|
145
include/utils/AssetDir.h
Normal file
145
include/utils/AssetDir.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Access a chunk of the asset hierarchy as if it were a single directory.
|
||||
//
|
||||
#ifndef __LIBS_ASSETDIR_H
|
||||
#define __LIBS_ASSETDIR_H
|
||||
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/SortedVector.h>
|
||||
#include <utils/misc.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* This provides vector-style access to a directory. We do this rather
|
||||
* than modeling opendir/readdir access because it's simpler and the
|
||||
* nature of the operation requires us to have all data on hand anyway.
|
||||
*
|
||||
* The list of files will be sorted in ascending order by ASCII value.
|
||||
*
|
||||
* The contents are populated by our friend, the AssetManager.
|
||||
*/
|
||||
class AssetDir {
|
||||
public:
|
||||
AssetDir(void)
|
||||
: mFileInfo(NULL)
|
||||
{}
|
||||
virtual ~AssetDir(void) {
|
||||
delete mFileInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Vector-style access.
|
||||
*/
|
||||
size_t getFileCount(void) { return mFileInfo->size(); }
|
||||
const String8& getFileName(int idx) {
|
||||
return mFileInfo->itemAt(idx).getFileName();
|
||||
}
|
||||
const String8& getSourceName(int idx) {
|
||||
return mFileInfo->itemAt(idx).getSourceName();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the type of a file (usually regular or directory).
|
||||
*/
|
||||
FileType getFileType(int idx) {
|
||||
return mFileInfo->itemAt(idx).getFileType();
|
||||
}
|
||||
|
||||
private:
|
||||
/* these operations are not implemented */
|
||||
AssetDir(const AssetDir& src);
|
||||
const AssetDir& operator=(const AssetDir& src);
|
||||
|
||||
friend class AssetManager;
|
||||
|
||||
/*
|
||||
* This holds information about files in the asset hierarchy.
|
||||
*/
|
||||
class FileInfo {
|
||||
public:
|
||||
FileInfo(void) {}
|
||||
FileInfo(const String8& path) // useful for e.g. svect.indexOf
|
||||
: mFileName(path), mFileType(kFileTypeUnknown)
|
||||
{}
|
||||
~FileInfo(void) {}
|
||||
FileInfo(const FileInfo& src) {
|
||||
copyMembers(src);
|
||||
}
|
||||
const FileInfo& operator= (const FileInfo& src) {
|
||||
if (this != &src)
|
||||
copyMembers(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void copyMembers(const FileInfo& src) {
|
||||
mFileName = src.mFileName;
|
||||
mFileType = src.mFileType;
|
||||
mSourceName = src.mSourceName;
|
||||
}
|
||||
|
||||
/* need this for SortedVector; must compare only on file name */
|
||||
bool operator< (const FileInfo& rhs) const {
|
||||
return mFileName < rhs.mFileName;
|
||||
}
|
||||
|
||||
/* used by AssetManager */
|
||||
bool operator== (const FileInfo& rhs) const {
|
||||
return mFileName == rhs.mFileName;
|
||||
}
|
||||
|
||||
void set(const String8& path, FileType type) {
|
||||
mFileName = path;
|
||||
mFileType = type;
|
||||
}
|
||||
|
||||
const String8& getFileName(void) const { return mFileName; }
|
||||
void setFileName(const String8& path) { mFileName = path; }
|
||||
|
||||
FileType getFileType(void) const { return mFileType; }
|
||||
void setFileType(FileType type) { mFileType = type; }
|
||||
|
||||
const String8& getSourceName(void) const { return mSourceName; }
|
||||
void setSourceName(const String8& path) { mSourceName = path; }
|
||||
|
||||
/*
|
||||
* Handy utility for finding an entry in a sorted vector of FileInfo.
|
||||
* Returns the index of the matching entry, or -1 if none found.
|
||||
*/
|
||||
static int findEntry(const SortedVector<FileInfo>* pVector,
|
||||
const String8& fileName);
|
||||
|
||||
private:
|
||||
String8 mFileName; // filename only
|
||||
FileType mFileType; // regular, directory, etc
|
||||
|
||||
String8 mSourceName; // currently debug-only
|
||||
};
|
||||
|
||||
/* AssetManager uses this to initialize us */
|
||||
void setFileList(SortedVector<FileInfo>* list) { mFileInfo = list; }
|
||||
|
||||
SortedVector<FileInfo>* mFileInfo;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ASSETDIR_H
|
323
include/utils/AssetManager.h
Normal file
323
include/utils/AssetManager.h
Normal file
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Asset management class. AssetManager objects are thread-safe.
|
||||
//
|
||||
#ifndef __LIBS_ASSETMANAGER_H
|
||||
#define __LIBS_ASSETMANAGER_H
|
||||
|
||||
#include <utils/Asset.h>
|
||||
#include <utils/AssetDir.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/ZipFileRO.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class Asset; // fwd decl for things that include Asset.h first
|
||||
class ResTable;
|
||||
struct ResTable_config;
|
||||
|
||||
/*
|
||||
* Every application that uses assets needs one instance of this. A
|
||||
* single instance may be shared across multiple threads, and a single
|
||||
* thread may have more than one instance (the latter is discouraged).
|
||||
*
|
||||
* The purpose of the AssetManager is to create Asset objects. To do
|
||||
* this efficiently it may cache information about the locations of
|
||||
* files it has seen. This can be controlled with the "cacheMode"
|
||||
* argument.
|
||||
*
|
||||
* The asset hierarchy may be examined like a filesystem, using
|
||||
* AssetDir objects to peruse a single directory.
|
||||
*/
|
||||
class AssetManager {
|
||||
public:
|
||||
typedef enum CacheMode {
|
||||
CACHE_UNKNOWN = 0,
|
||||
CACHE_OFF, // don't try to cache file locations
|
||||
CACHE_DEFER, // construct cache as pieces are needed
|
||||
//CACHE_SCAN, // scan full(!) asset hierarchy at init() time
|
||||
} CacheMode;
|
||||
|
||||
AssetManager(CacheMode cacheMode = CACHE_OFF);
|
||||
virtual ~AssetManager(void);
|
||||
|
||||
static int32_t getGlobalCount();
|
||||
|
||||
/*
|
||||
* Add a new source for assets. This can be called multiple times to
|
||||
* look in multiple places for assets. It can be either a directory (for
|
||||
* finding assets as raw files on the disk) or a ZIP file. This newly
|
||||
* added asset path will be examined first when searching for assets,
|
||||
* before any that were previously added.
|
||||
*
|
||||
* Returns "true" on success, "false" on failure. If 'cookie' is non-NULL,
|
||||
* then on success, *cookie is set to the value corresponding to the
|
||||
* newly-added asset source.
|
||||
*/
|
||||
bool addAssetPath(const String8& path, void** cookie);
|
||||
|
||||
/*
|
||||
* Convenience for adding the standard system assets. Uses the
|
||||
* ANDROID_ROOT environment variable to find them.
|
||||
*/
|
||||
bool addDefaultAssets();
|
||||
|
||||
/*
|
||||
* Iterate over the asset paths in this manager. (Previously
|
||||
* added via addAssetPath() and addDefaultAssets().) On first call,
|
||||
* 'cookie' must be NULL, resulting in the first cookie being returned.
|
||||
* Each next cookie will be returned there-after, until NULL indicating
|
||||
* the end has been reached.
|
||||
*/
|
||||
void* nextAssetPath(void* cookie) const;
|
||||
|
||||
/*
|
||||
* Return an asset path in the manager. 'which' must be between 0 and
|
||||
* countAssetPaths().
|
||||
*/
|
||||
String8 getAssetPath(void* cookie) const;
|
||||
|
||||
/*
|
||||
* Set the current locale and vendor. The locale can change during
|
||||
* the lifetime of an AssetManager if the user updates the device's
|
||||
* language setting. The vendor is less likely to change.
|
||||
*
|
||||
* Pass in NULL to indicate no preference.
|
||||
*/
|
||||
void setLocale(const char* locale);
|
||||
void setVendor(const char* vendor);
|
||||
|
||||
/*
|
||||
* Choose screen orientation for resources values returned.
|
||||
*/
|
||||
void setConfiguration(const ResTable_config& config, const char* locale = NULL);
|
||||
|
||||
typedef Asset::AccessMode AccessMode; // typing shortcut
|
||||
|
||||
/*
|
||||
* Open an asset.
|
||||
*
|
||||
* This will search through locale-specific and vendor-specific
|
||||
* directories and packages to find the file.
|
||||
*
|
||||
* The object returned does not depend on the AssetManager. It should
|
||||
* be freed by calling Asset::close().
|
||||
*/
|
||||
Asset* open(const char* fileName, AccessMode mode);
|
||||
|
||||
/*
|
||||
* Open a non-asset file as an asset.
|
||||
*
|
||||
* This is for opening files that are included in an asset package
|
||||
* but aren't assets. These sit outside the usual "locale/vendor"
|
||||
* path hierarchy, and will not be seen by "AssetDir" or included
|
||||
* in our filename cache.
|
||||
*/
|
||||
Asset* openNonAsset(const char* fileName, AccessMode mode);
|
||||
|
||||
/*
|
||||
* Explicit non-asset file. The file explicitly named by the cookie (the
|
||||
* resource set to look in) and fileName will be opened and returned.
|
||||
*/
|
||||
Asset* openNonAsset(void* cookie, const char* fileName, AccessMode mode);
|
||||
|
||||
/*
|
||||
* Open a directory within the asset hierarchy.
|
||||
*
|
||||
* The contents of the directory are an amalgam of vendor-specific,
|
||||
* locale-specific, and generic assets stored loosely or in asset
|
||||
* packages. Depending on the cache setting and previous accesses,
|
||||
* this call may incur significant disk overhead.
|
||||
*
|
||||
* To open the top-level directory, pass in "".
|
||||
*/
|
||||
AssetDir* openDir(const char* dirName);
|
||||
|
||||
/*
|
||||
* Get the type of a file in the asset hierarchy. They will either
|
||||
* be "regular" or "directory". [Currently only works for "regular".]
|
||||
*
|
||||
* Can also be used as a quick test for existence of a file.
|
||||
*/
|
||||
FileType getFileType(const char* fileName);
|
||||
|
||||
/*
|
||||
* Return the complete resource table to find things in the package.
|
||||
*/
|
||||
const ResTable& getResources(bool required = true) const;
|
||||
|
||||
/*
|
||||
* Discard cached filename information. This only needs to be called
|
||||
* if somebody has updated the set of "loose" files, and we want to
|
||||
* discard our cached notion of what's where.
|
||||
*/
|
||||
void purge(void) { purgeFileNameCacheLocked(); }
|
||||
|
||||
/*
|
||||
* Return true if the files this AssetManager references are all
|
||||
* up-to-date (have not been changed since it was created). If false
|
||||
* is returned, you will need to create a new AssetManager to get
|
||||
* the current data.
|
||||
*/
|
||||
bool isUpToDate();
|
||||
|
||||
/**
|
||||
* Get the known locales for this asset manager object.
|
||||
*/
|
||||
void getLocales(Vector<String8>* locales) const;
|
||||
|
||||
private:
|
||||
struct asset_path
|
||||
{
|
||||
String8 path;
|
||||
FileType type;
|
||||
};
|
||||
|
||||
Asset* openInPathLocked(const char* fileName, AccessMode mode,
|
||||
const asset_path& path);
|
||||
Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
|
||||
const asset_path& path);
|
||||
Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
|
||||
const asset_path& path, const char* locale, const char* vendor);
|
||||
String8 createPathNameLocked(const asset_path& path, const char* locale,
|
||||
const char* vendor);
|
||||
String8 createPathNameLocked(const asset_path& path, const char* rootDir);
|
||||
String8 createZipSourceNameLocked(const String8& zipFileName,
|
||||
const String8& dirName, const String8& fileName);
|
||||
|
||||
ZipFileRO* getZipFileLocked(const asset_path& path);
|
||||
Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
|
||||
Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
|
||||
const ZipEntryRO entry, AccessMode mode, const String8& entryName);
|
||||
|
||||
bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
|
||||
const asset_path& path, const char* rootDir, const char* dirName);
|
||||
SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
|
||||
bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
|
||||
const asset_path& path, const char* rootDir, const char* dirName);
|
||||
void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
|
||||
const SortedVector<AssetDir::FileInfo>* pContents);
|
||||
|
||||
void loadFileNameCacheLocked(void);
|
||||
void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
|
||||
const char* dirName);
|
||||
bool fncScanAndMergeDirLocked(
|
||||
SortedVector<AssetDir::FileInfo>* pMergedInfo,
|
||||
const asset_path& path, const char* locale, const char* vendor,
|
||||
const char* dirName);
|
||||
void purgeFileNameCacheLocked(void);
|
||||
|
||||
const ResTable* getResTable(bool required = true) const;
|
||||
void setLocaleLocked(const char* locale);
|
||||
void updateResourceParamsLocked() const;
|
||||
|
||||
class SharedZip : public RefBase {
|
||||
public:
|
||||
static sp<SharedZip> get(const String8& path);
|
||||
|
||||
ZipFileRO* getZip();
|
||||
|
||||
Asset* getResourceTableAsset();
|
||||
Asset* setResourceTableAsset(Asset* asset);
|
||||
|
||||
bool isUpToDate();
|
||||
|
||||
protected:
|
||||
~SharedZip();
|
||||
|
||||
private:
|
||||
SharedZip(const String8& path, time_t modWhen);
|
||||
SharedZip(); // <-- not implemented
|
||||
|
||||
String8 mPath;
|
||||
ZipFileRO* mZipFile;
|
||||
time_t mModWhen;
|
||||
|
||||
Asset* mResourceTableAsset;
|
||||
|
||||
static Mutex gLock;
|
||||
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
|
||||
};
|
||||
|
||||
/*
|
||||
* Manage a set of Zip files. For each file we need a pointer to the
|
||||
* ZipFile and a time_t with the file's modification date.
|
||||
*
|
||||
* We currently only have two zip files (current app, "common" app).
|
||||
* (This was originally written for 8, based on app/locale/vendor.)
|
||||
*/
|
||||
class ZipSet {
|
||||
public:
|
||||
ZipSet(void);
|
||||
~ZipSet(void);
|
||||
|
||||
/*
|
||||
* Return a ZipFileRO structure for a ZipFileRO with the specified
|
||||
* parameters.
|
||||
*/
|
||||
ZipFileRO* getZip(const String8& path);
|
||||
|
||||
Asset* getZipResourceTable(const String8& path);
|
||||
Asset* setZipResourceTable(const String8& path, Asset* asset);
|
||||
|
||||
// generate path, e.g. "common/en-US-noogle.zip"
|
||||
static String8 getPathName(const char* path);
|
||||
|
||||
bool isUpToDate();
|
||||
|
||||
private:
|
||||
void closeZip(int idx);
|
||||
|
||||
int getIndex(const String8& zip) const;
|
||||
mutable Vector<String8> mZipPath;
|
||||
mutable Vector<sp<SharedZip> > mZipFile;
|
||||
};
|
||||
|
||||
// Protect all internal state.
|
||||
mutable Mutex mLock;
|
||||
|
||||
ZipSet mZipSet;
|
||||
|
||||
Vector<asset_path> mAssetPaths;
|
||||
char* mLocale;
|
||||
char* mVendor;
|
||||
|
||||
mutable ResTable* mResources;
|
||||
ResTable_config* mConfig;
|
||||
|
||||
/*
|
||||
* Cached data for "loose" files. This lets us avoid poking at the
|
||||
* filesystem when searching for loose assets. Each entry is the
|
||||
* "extended partial" path, e.g. "default/default/foo/bar.txt". The
|
||||
* full set of files is present, including ".EXCLUDE" entries.
|
||||
*
|
||||
* We do not cache directory names. We don't retain the ".gz",
|
||||
* because to our clients "foo" and "foo.gz" both look like "foo".
|
||||
*/
|
||||
CacheMode mCacheMode; // is the cache enabled?
|
||||
bool mCacheValid; // clear when locale or vendor changes
|
||||
SortedVector<AssetDir::FileInfo> mCache;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ASSETMANAGER_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
|
103
include/utils/Binder.h
Normal file
103
include/utils/Binder.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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 ANDROID_BINDER_H
|
||||
#define ANDROID_BINDER_H
|
||||
|
||||
#include <utils/IBinder.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class BBinder : public IBinder
|
||||
{
|
||||
public:
|
||||
BBinder();
|
||||
|
||||
virtual String16 getInterfaceDescriptor() const;
|
||||
virtual bool isBinderAlive() const;
|
||||
virtual status_t pingBinder();
|
||||
virtual status_t dump(int fd, const Vector<String16>& args);
|
||||
|
||||
virtual status_t transact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
|
||||
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
|
||||
void* cookie = NULL,
|
||||
uint32_t flags = 0);
|
||||
|
||||
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
|
||||
void* cookie = NULL,
|
||||
uint32_t flags = 0,
|
||||
wp<DeathRecipient>* outRecipient = NULL);
|
||||
|
||||
virtual void attachObject( const void* objectID,
|
||||
void* object,
|
||||
void* cleanupCookie,
|
||||
object_cleanup_func func);
|
||||
virtual void* findObject(const void* objectID) const;
|
||||
virtual void detachObject(const void* objectID);
|
||||
|
||||
virtual BBinder* localBinder();
|
||||
|
||||
protected:
|
||||
virtual ~BBinder();
|
||||
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
|
||||
private:
|
||||
BBinder(const BBinder& o);
|
||||
BBinder& operator=(const BBinder& o);
|
||||
|
||||
class Extras;
|
||||
|
||||
Extras* mExtras;
|
||||
void* mReserved0;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class BpRefBase : public virtual RefBase
|
||||
{
|
||||
protected:
|
||||
BpRefBase(const sp<IBinder>& o);
|
||||
virtual ~BpRefBase();
|
||||
virtual void onFirstRef();
|
||||
virtual void onLastStrongRef(const void* id);
|
||||
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
|
||||
|
||||
inline IBinder* remote() { return mRemote; }
|
||||
inline IBinder* remote() const { return mRemote; }
|
||||
|
||||
private:
|
||||
BpRefBase(const BpRefBase& o);
|
||||
BpRefBase& operator=(const BpRefBase& o);
|
||||
|
||||
IBinder* const mRemote;
|
||||
RefBase::weakref_type* mRefs;
|
||||
volatile int32_t mState;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_BINDER_H
|
122
include/utils/BpBinder.h
Normal file
122
include/utils/BpBinder.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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_BPBINDER_H
|
||||
#define ANDROID_BPBINDER_H
|
||||
|
||||
#include <utils/IBinder.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class BpBinder : public IBinder
|
||||
{
|
||||
public:
|
||||
BpBinder(int32_t handle);
|
||||
|
||||
inline int32_t handle() const { return mHandle; }
|
||||
|
||||
virtual String16 getInterfaceDescriptor() const;
|
||||
virtual bool isBinderAlive() const;
|
||||
virtual status_t pingBinder();
|
||||
virtual status_t dump(int fd, const Vector<String16>& args);
|
||||
|
||||
virtual status_t transact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
|
||||
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
|
||||
void* cookie = NULL,
|
||||
uint32_t flags = 0);
|
||||
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
|
||||
void* cookie = NULL,
|
||||
uint32_t flags = 0,
|
||||
wp<DeathRecipient>* outRecipient = NULL);
|
||||
|
||||
virtual void attachObject( const void* objectID,
|
||||
void* object,
|
||||
void* cleanupCookie,
|
||||
object_cleanup_func func);
|
||||
virtual void* findObject(const void* objectID) const;
|
||||
virtual void detachObject(const void* objectID);
|
||||
|
||||
virtual BpBinder* remoteBinder();
|
||||
|
||||
status_t setConstantData(const void* data, size_t size);
|
||||
void sendObituary();
|
||||
|
||||
class ObjectManager
|
||||
{
|
||||
public:
|
||||
ObjectManager();
|
||||
~ObjectManager();
|
||||
|
||||
void attach( const void* objectID,
|
||||
void* object,
|
||||
void* cleanupCookie,
|
||||
IBinder::object_cleanup_func func);
|
||||
void* find(const void* objectID) const;
|
||||
void detach(const void* objectID);
|
||||
|
||||
void kill();
|
||||
|
||||
private:
|
||||
ObjectManager(const ObjectManager&);
|
||||
ObjectManager& operator=(const ObjectManager&);
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
void* object;
|
||||
void* cleanupCookie;
|
||||
IBinder::object_cleanup_func func;
|
||||
};
|
||||
|
||||
KeyedVector<const void*, entry_t> mObjects;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual ~BpBinder();
|
||||
virtual void onFirstRef();
|
||||
virtual void onLastStrongRef(const void* id);
|
||||
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
|
||||
|
||||
private:
|
||||
const int32_t mHandle;
|
||||
|
||||
struct Obituary {
|
||||
wp<DeathRecipient> recipient;
|
||||
void* cookie;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
void reportOneDeath(const Obituary& obit);
|
||||
|
||||
mutable Mutex mLock;
|
||||
volatile int32_t mAlive;
|
||||
volatile int32_t mObitsSent;
|
||||
Vector<Obituary>* mObituaries;
|
||||
ObjectManager mObjects;
|
||||
Parcel* mConstantData;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_BPBINDER_H
|
107
include/utils/Buffer.h
Normal file
107
include/utils/Buffer.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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 __UTILS_BUFFER_H__
|
||||
#define __UTILS_BUFFER_H__ 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class Buffer
|
||||
{
|
||||
private:
|
||||
char *buf;
|
||||
int bufsiz;
|
||||
int used;
|
||||
void ensureCapacity(int len);
|
||||
|
||||
void
|
||||
makeRoomFor(int len)
|
||||
{
|
||||
if (len + used >= bufsiz) {
|
||||
bufsiz = (len + used) * 3/2 + 2;
|
||||
char *blah = new char[bufsiz];
|
||||
|
||||
memcpy(blah, buf, used);
|
||||
delete[] buf;
|
||||
buf = blah;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Buffer()
|
||||
{
|
||||
bufsiz = 16;
|
||||
buf = new char[bufsiz];
|
||||
clear();
|
||||
}
|
||||
|
||||
~Buffer()
|
||||
{
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
buf[0] = '\0';
|
||||
used = 0;
|
||||
}
|
||||
|
||||
int
|
||||
length()
|
||||
{
|
||||
return used;
|
||||
}
|
||||
|
||||
void
|
||||
append(const char c)
|
||||
{
|
||||
makeRoomFor(1);
|
||||
buf[used] = c;
|
||||
used++;
|
||||
buf[used] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
append(const char *s, int len)
|
||||
{
|
||||
makeRoomFor(len);
|
||||
|
||||
memcpy(buf + used, s, len);
|
||||
used += len;
|
||||
buf[used] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
append(const char *s)
|
||||
{
|
||||
append(s, strlen(s));
|
||||
}
|
||||
|
||||
char *
|
||||
getBytes()
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
67
include/utils/BufferedTextOutput.h
Normal file
67
include/utils/BufferedTextOutput.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 ANDROID_BUFFEREDTEXTOUTPUT_H
|
||||
#define ANDROID_BUFFEREDTEXTOUTPUT_H
|
||||
|
||||
#include <utils/TextOutput.h>
|
||||
#include <utils/threads.h>
|
||||
#include <cutils/uio.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class BufferedTextOutput : public TextOutput
|
||||
{
|
||||
public:
|
||||
//** Flags for constructor */
|
||||
enum {
|
||||
MULTITHREADED = 0x0001
|
||||
};
|
||||
|
||||
BufferedTextOutput(uint32_t flags = 0);
|
||||
virtual ~BufferedTextOutput();
|
||||
|
||||
virtual status_t print(const char* txt, size_t len);
|
||||
virtual void moveIndent(int delta);
|
||||
|
||||
virtual void pushBundle();
|
||||
virtual void popBundle();
|
||||
|
||||
protected:
|
||||
virtual status_t writeLines(const struct iovec& vec, size_t N) = 0;
|
||||
|
||||
private:
|
||||
struct BufferState;
|
||||
struct ThreadState;
|
||||
|
||||
static ThreadState*getThreadState();
|
||||
static void threadDestructor(void *st);
|
||||
|
||||
BufferState*getBuffer() const;
|
||||
|
||||
uint32_t mFlags;
|
||||
const int32_t mSeq;
|
||||
const int32_t mIndex;
|
||||
|
||||
Mutex mLock;
|
||||
BufferState* mGlobalState;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_BUFFEREDTEXTOUTPUT_H
|
69
include/utils/ByteOrder.h
Normal file
69
include/utils/ByteOrder.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
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 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
|
||||
|
||||
#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>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
class CallStack
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
MAX_DEPTH = 31
|
||||
};
|
||||
|
||||
CallStack();
|
||||
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=0, int32_t maxDepth=MAX_DEPTH);
|
||||
|
||||
// Dump a stack trace to the log
|
||||
void dump(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:
|
||||
// Internal helper function
|
||||
String8 toStringSingleLevel(const char* prefix, int32_t level) const;
|
||||
|
||||
size_t mCount;
|
||||
const void* mStack[MAX_DEPTH];
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_CALLSTACK_H
|
45
include/utils/Debug.h
Normal file
45
include/utils/Debug.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Debugging tools. These should be able to be stripped
|
||||
// in release builds.
|
||||
//
|
||||
#ifndef ANDROID_DEBUG_H
|
||||
#define ANDROID_DEBUG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
template<bool> struct CompileTimeAssert;
|
||||
template<> struct CompileTimeAssert<true> {};
|
||||
|
||||
const char* stringForIndent(int32_t indentLevel);
|
||||
|
||||
typedef void (*debugPrintFunc)(void* cookie, const char* txt);
|
||||
|
||||
void printTypeCode(uint32_t typeCode,
|
||||
debugPrintFunc func = 0, void* cookie = 0);
|
||||
void printHexData(int32_t indent, const void *buf, size_t length,
|
||||
size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
|
||||
size_t alignment=0, bool cArrayStyle=false,
|
||||
debugPrintFunc func = 0, void* cookie = 0);
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_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*/
|
87
include/utils/Errors.h
Normal file
87
include/utils/Errors.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 = -ETIME,
|
||||
UNKNOWN_TRANSACTION = -EBADMSG,
|
||||
#else
|
||||
BAD_INDEX = -E2BIG,
|
||||
NOT_ENOUGH_DATA = 0x80000003,
|
||||
WOULD_BLOCK = 0x80000004,
|
||||
TIMED_OUT = 0x80000005,
|
||||
UNKNOWN_TRANSACTION = 0x80000006,
|
||||
#endif
|
||||
};
|
||||
|
||||
// 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
|
134
include/utils/FileMap.h
Normal file
134
include/utils/FileMap.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#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,
|
||||
off_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.
|
||||
*/
|
||||
off_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"
|
||||
off_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
|
159
include/utils/IBinder.h
Normal file
159
include/utils/IBinder.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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 ANDROID_IBINDER_H
|
||||
#define ANDROID_IBINDER_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
|
||||
#define B_PACK_CHARS(c1, c2, c3, c4) \
|
||||
((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class BBinder;
|
||||
class BpBinder;
|
||||
class IInterface;
|
||||
class Parcel;
|
||||
|
||||
/**
|
||||
* Base class and low-level protocol for a remotable object.
|
||||
* You can derive from this class to create an object for which other
|
||||
* processes can hold references to it. Communication between processes
|
||||
* (method calls, property get and set) is down through a low-level
|
||||
* protocol implemented on top of the transact() API.
|
||||
*/
|
||||
class IBinder : public virtual RefBase
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
FIRST_CALL_TRANSACTION = 0x00000001,
|
||||
LAST_CALL_TRANSACTION = 0x00ffffff,
|
||||
|
||||
PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
|
||||
DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
|
||||
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
|
||||
|
||||
// Corresponds to tfOneWay -- an asynchronous call.
|
||||
FLAG_ONEWAY = 0x00000001
|
||||
};
|
||||
|
||||
inline IBinder() { }
|
||||
|
||||
/**
|
||||
* Check if this IBinder implements the interface named by
|
||||
* @a descriptor. If it does, the base pointer to it is returned,
|
||||
* which you can safely static_cast<> to the concrete C++ interface.
|
||||
*/
|
||||
virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
|
||||
|
||||
/**
|
||||
* Return the canonical name of the interface provided by this IBinder
|
||||
* object.
|
||||
*/
|
||||
virtual String16 getInterfaceDescriptor() const = 0;
|
||||
|
||||
virtual bool isBinderAlive() const = 0;
|
||||
virtual status_t pingBinder() = 0;
|
||||
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
|
||||
|
||||
virtual status_t transact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0) = 0;
|
||||
|
||||
/**
|
||||
* This method allows you to add data that is transported through
|
||||
* IPC along with your IBinder pointer. When implementing a Binder
|
||||
* object, override it to write your desired data in to @a outData.
|
||||
* You can then call getConstantData() on your IBinder to retrieve
|
||||
* that data, from any process. You MUST return the number of bytes
|
||||
* written in to the parcel (including padding).
|
||||
*/
|
||||
class DeathRecipient : public virtual RefBase
|
||||
{
|
||||
public:
|
||||
virtual void binderDied(const wp<IBinder>& who) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the @a recipient for a notification if this binder
|
||||
* goes away. If this binder object unexpectedly goes away
|
||||
* (typically because its hosting process has been killed),
|
||||
* then DeathRecipient::binderDied() will be called with a referene
|
||||
* to this.
|
||||
*
|
||||
* The @a cookie is optional -- if non-NULL, it should be a
|
||||
* memory address that you own (that is, you know it is unique).
|
||||
*
|
||||
* @note You will only receive death notifications for remote binders,
|
||||
* as local binders by definition can't die without you dying as well.
|
||||
* Trying to use this function on a local binder will result in an
|
||||
* INVALID_OPERATION code being returned and nothing happening.
|
||||
*
|
||||
* @note This link always holds a weak reference to its recipient.
|
||||
*
|
||||
* @note You will only receive a weak reference to the dead
|
||||
* binder. You should not try to promote this to a strong reference.
|
||||
* (Nor should you need to, as there is nothing useful you can
|
||||
* directly do with it now that it has passed on.)
|
||||
*/
|
||||
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
|
||||
void* cookie = NULL,
|
||||
uint32_t flags = 0) = 0;
|
||||
|
||||
/**
|
||||
* Remove a previously registered death notification.
|
||||
* The @a recipient will no longer be called if this object
|
||||
* dies. The @a cookie is optional. If non-NULL, you can
|
||||
* supply a NULL @a recipient, and the recipient previously
|
||||
* added with that cookie will be unlinked.
|
||||
*/
|
||||
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
|
||||
void* cookie = NULL,
|
||||
uint32_t flags = 0,
|
||||
wp<DeathRecipient>* outRecipient = NULL) = 0;
|
||||
|
||||
virtual bool checkSubclass(const void* subclassID) const;
|
||||
|
||||
typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
|
||||
|
||||
virtual void attachObject( const void* objectID,
|
||||
void* object,
|
||||
void* cleanupCookie,
|
||||
object_cleanup_func func) = 0;
|
||||
virtual void* findObject(const void* objectID) const = 0;
|
||||
virtual void detachObject(const void* objectID) = 0;
|
||||
|
||||
virtual BBinder* localBinder();
|
||||
virtual BpBinder* remoteBinder();
|
||||
|
||||
protected:
|
||||
inline virtual ~IBinder() { }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_IBINDER_H
|
135
include/utils/IInterface.h
Normal file
135
include/utils/IInterface.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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_IINTERFACE_H
|
||||
#define ANDROID_IINTERFACE_H
|
||||
|
||||
#include <utils/Binder.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class IInterface : public virtual RefBase
|
||||
{
|
||||
public:
|
||||
sp<IBinder> asBinder();
|
||||
sp<const IBinder> asBinder() const;
|
||||
|
||||
protected:
|
||||
virtual IBinder* onAsBinder() = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<typename INTERFACE>
|
||||
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
|
||||
{
|
||||
return INTERFACE::asInterface(obj);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<typename INTERFACE>
|
||||
class BnInterface : public INTERFACE, public BBinder
|
||||
{
|
||||
public:
|
||||
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
|
||||
virtual String16 getInterfaceDescriptor() const;
|
||||
|
||||
protected:
|
||||
virtual IBinder* onAsBinder();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
template<typename INTERFACE>
|
||||
class BpInterface : public INTERFACE, public BpRefBase
|
||||
{
|
||||
public:
|
||||
BpInterface(const sp<IBinder>& remote);
|
||||
|
||||
protected:
|
||||
virtual IBinder* onAsBinder();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#define DECLARE_META_INTERFACE(INTERFACE) \
|
||||
static const String16 descriptor; \
|
||||
static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
|
||||
virtual String16 getInterfaceDescriptor() const; \
|
||||
|
||||
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
|
||||
const String16 I##INTERFACE::descriptor(NAME); \
|
||||
String16 I##INTERFACE::getInterfaceDescriptor() const { \
|
||||
return I##INTERFACE::descriptor; \
|
||||
} \
|
||||
sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
|
||||
{ \
|
||||
sp<I##INTERFACE> intr; \
|
||||
if (obj != NULL) { \
|
||||
intr = static_cast<I##INTERFACE*>( \
|
||||
obj->queryLocalInterface( \
|
||||
I##INTERFACE::descriptor).get()); \
|
||||
if (intr == NULL) { \
|
||||
intr = new Bp##INTERFACE(obj); \
|
||||
} \
|
||||
} \
|
||||
return intr; \
|
||||
} \
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// No user-servicable parts after this...
|
||||
|
||||
template<typename INTERFACE>
|
||||
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
|
||||
const String16& _descriptor)
|
||||
{
|
||||
if (_descriptor == INTERFACE::descriptor) return this;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<typename INTERFACE>
|
||||
inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
|
||||
{
|
||||
return INTERFACE::getInterfaceDescriptor();
|
||||
}
|
||||
|
||||
template<typename INTERFACE>
|
||||
IBinder* BnInterface<INTERFACE>::onAsBinder()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
template<typename INTERFACE>
|
||||
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
|
||||
: BpRefBase(remote)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename INTERFACE>
|
||||
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
|
||||
{
|
||||
return remote();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IINTERFACE_H
|
94
include/utils/IMemory.h
Normal file
94
include/utils/IMemory.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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_IMEMORY_H
|
||||
#define ANDROID_IMEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/IInterface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IMemoryHeap : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(MemoryHeap);
|
||||
|
||||
// flags returned by getFlags()
|
||||
enum {
|
||||
READ_ONLY = 0x00000001,
|
||||
MAP_ONCE = 0x00000002
|
||||
};
|
||||
|
||||
virtual int getHeapID() const = 0;
|
||||
virtual void* getBase() const = 0;
|
||||
virtual size_t getSize() const = 0;
|
||||
virtual uint32_t getFlags() const = 0;
|
||||
|
||||
// these are there just for backward source compatibility
|
||||
int32_t heapID() const { return getHeapID(); }
|
||||
void* base() const { return getBase(); }
|
||||
size_t virtualSize() const { return getSize(); }
|
||||
};
|
||||
|
||||
class BnMemoryHeap : public BnInterface<IMemoryHeap>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact(
|
||||
uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IMemory : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(Memory);
|
||||
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
|
||||
|
||||
// helpers
|
||||
void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
|
||||
void* pointer() const;
|
||||
size_t size() const;
|
||||
ssize_t offset() const;
|
||||
};
|
||||
|
||||
class BnMemory : public BnInterface<IMemory>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact(
|
||||
uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEMORY_H
|
110
include/utils/IPCThreadState.h
Normal file
110
include/utils/IPCThreadState.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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_IPC_THREAD_STATE_H
|
||||
#define ANDROID_IPC_THREAD_STATE_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/ProcessState.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#ifdef HAVE_WIN32_PROC
|
||||
typedef int uid_t;
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class IPCThreadState
|
||||
{
|
||||
public:
|
||||
static IPCThreadState* self();
|
||||
|
||||
sp<ProcessState> process();
|
||||
|
||||
status_t clearLastError();
|
||||
|
||||
int getCallingPid();
|
||||
int getCallingUid();
|
||||
|
||||
int64_t clearCallingIdentity();
|
||||
void restoreCallingIdentity(int64_t token);
|
||||
|
||||
void flushCommands();
|
||||
|
||||
void joinThreadPool(bool isMain = true);
|
||||
|
||||
// Stop the local process.
|
||||
void stopProcess(bool immediate = true);
|
||||
|
||||
status_t transact(int32_t handle,
|
||||
uint32_t code, const Parcel& data,
|
||||
Parcel* reply, uint32_t flags);
|
||||
|
||||
void incStrongHandle(int32_t handle);
|
||||
void decStrongHandle(int32_t handle);
|
||||
void incWeakHandle(int32_t handle);
|
||||
void decWeakHandle(int32_t handle);
|
||||
status_t attemptIncStrongHandle(int32_t handle);
|
||||
static void expungeHandle(int32_t handle, IBinder* binder);
|
||||
status_t requestDeathNotification( int32_t handle,
|
||||
BpBinder* proxy);
|
||||
status_t clearDeathNotification( int32_t handle,
|
||||
BpBinder* proxy);
|
||||
|
||||
static void shutdown();
|
||||
|
||||
private:
|
||||
IPCThreadState();
|
||||
~IPCThreadState();
|
||||
|
||||
status_t sendReply(const Parcel& reply, uint32_t flags);
|
||||
status_t waitForResponse(Parcel *reply,
|
||||
status_t *acquireResult=NULL);
|
||||
status_t talkWithDriver(bool doReceive=true);
|
||||
status_t writeTransactionData(int32_t cmd,
|
||||
uint32_t binderFlags,
|
||||
int32_t handle,
|
||||
uint32_t code,
|
||||
const Parcel& data,
|
||||
status_t* statusBuffer);
|
||||
status_t executeCommand(int32_t command);
|
||||
|
||||
void clearCaller();
|
||||
|
||||
static void threadDestructor(void *st);
|
||||
static void freeBuffer(Parcel* parcel,
|
||||
const uint8_t* data, size_t dataSize,
|
||||
const size_t* objects, size_t objectsSize,
|
||||
void* cookie);
|
||||
|
||||
const sp<ProcessState> mProcess;
|
||||
Vector<BBinder*> mPendingStrongDerefs;
|
||||
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
|
||||
|
||||
Parcel mIn;
|
||||
Parcel mOut;
|
||||
status_t mLastError;
|
||||
pid_t mCallingPid;
|
||||
uid_t mCallingUid;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_IPC_THREAD_STATE_H
|
56
include/utils/IPermissionController.h
Normal file
56
include/utils/IPermissionController.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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_IPERMISSION_CONTROLLER_H
|
||||
#define ANDROID_IPERMISSION_CONTROLLER_H
|
||||
|
||||
#include <utils/IInterface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class IPermissionController : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(PermissionController);
|
||||
|
||||
virtual bool checkPermission(const String16& permission,
|
||||
int32_t pid, int32_t uid) = 0;
|
||||
|
||||
enum {
|
||||
CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class BnPermissionController : public BnInterface<IPermissionController>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IPERMISSION_CONTROLLER_H
|
||||
|
98
include/utils/IServiceManager.h
Normal file
98
include/utils/IServiceManager.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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_ISERVICE_MANAGER_H
|
||||
#define ANDROID_ISERVICE_MANAGER_H
|
||||
|
||||
#include <utils/IInterface.h>
|
||||
#include <utils/IPermissionController.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/String16.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class IServiceManager : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(ServiceManager);
|
||||
|
||||
/**
|
||||
* Retrieve an existing service, blocking for a few seconds
|
||||
* if it doesn't yet exist.
|
||||
*/
|
||||
virtual sp<IBinder> getService( const String16& name) const = 0;
|
||||
|
||||
/**
|
||||
* Retrieve an existing service, non-blocking.
|
||||
*/
|
||||
virtual sp<IBinder> checkService( const String16& name) const = 0;
|
||||
|
||||
/**
|
||||
* Register a service.
|
||||
*/
|
||||
virtual status_t addService( const String16& name,
|
||||
const sp<IBinder>& service) = 0;
|
||||
|
||||
/**
|
||||
* Return list of all existing services.
|
||||
*/
|
||||
virtual Vector<String16> listServices() = 0;
|
||||
|
||||
enum {
|
||||
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
|
||||
CHECK_SERVICE_TRANSACTION,
|
||||
ADD_SERVICE_TRANSACTION,
|
||||
LIST_SERVICES_TRANSACTION,
|
||||
};
|
||||
};
|
||||
|
||||
sp<IServiceManager> defaultServiceManager();
|
||||
|
||||
template<typename INTERFACE>
|
||||
status_t getService(const String16& name, sp<INTERFACE>* outService)
|
||||
{
|
||||
const sp<IServiceManager> sm = defaultServiceManager();
|
||||
if (sm != NULL) {
|
||||
*outService = interface_cast<INTERFACE>(sm->getService(name));
|
||||
if ((*outService) != NULL) return NO_ERROR;
|
||||
}
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool checkCallingPermission(const String16& permission);
|
||||
bool checkCallingPermission(const String16& permission,
|
||||
int32_t* outPid, int32_t* outUid);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class BnServiceManager : public BnInterface<IServiceManager>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_ISERVICE_MANAGER_H
|
||||
|
201
include/utils/KeyedVector.h
Normal file
201
include/utils/KeyedVector.h
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* 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 <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 wether 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(); }
|
||||
//! setst the capacity. capacity can never be reduced less than size()
|
||||
inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); }
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* modifing 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;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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
|
||||
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 = indexOfKey(key);
|
||||
assert(i>=0);
|
||||
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 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 = indexOfKey(key);
|
||||
assert(i>=0);
|
||||
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.editValueAt(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 = indexOfKey(key);
|
||||
return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_KEYED_VECTOR_H
|
280
include/utils/List.h
Normal file
280
include/utils/List.h
Normal file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* 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". Do not use classes
|
||||
// starting with "_" directly.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_LIST_H
|
||||
#define _LIBS_UTILS_LIST_H
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* One element in the list.
|
||||
*/
|
||||
template<class T> class _ListNode {
|
||||
public:
|
||||
typedef _ListNode<T> _Node;
|
||||
|
||||
_ListNode(const T& val) : mVal(val) {}
|
||||
~_ListNode(void) {}
|
||||
|
||||
T& getRef(void) { return mVal; }
|
||||
void setVal(const T& val) { mVal = val; }
|
||||
|
||||
_Node* getPrev(void) const { return mpPrev; }
|
||||
void setPrev(_Node* ptr) { mpPrev = ptr; }
|
||||
_Node* getNext(void) const { return mpNext; }
|
||||
void setNext(_Node* ptr) { mpNext = ptr; }
|
||||
|
||||
private:
|
||||
T mVal;
|
||||
_Node* mpPrev;
|
||||
_Node* mpNext;
|
||||
};
|
||||
|
||||
/*
|
||||
* Iterator for walking through the list.
|
||||
*/
|
||||
template<class T, class Tref> class _ListIterator {
|
||||
public:
|
||||
typedef _ListIterator<T,Tref> _Iter;
|
||||
typedef _ListNode<T> _Node;
|
||||
|
||||
_ListIterator(void) {}
|
||||
_ListIterator(_Node* ptr) : mpNode(ptr) {}
|
||||
~_ListIterator(void) {}
|
||||
|
||||
/*
|
||||
* Dereference operator. Used to get at the juicy insides.
|
||||
*/
|
||||
Tref operator*() const { return mpNode->getRef(); }
|
||||
|
||||
/*
|
||||
* Iterator comparison.
|
||||
*/
|
||||
bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
|
||||
bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
|
||||
|
||||
/*
|
||||
* Incr/decr, used to move through the list.
|
||||
*/
|
||||
_Iter& operator++(void) { // pre-increment
|
||||
mpNode = mpNode->getNext();
|
||||
return *this;
|
||||
}
|
||||
_Iter operator++(int) { // post-increment
|
||||
_Iter tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
_Iter& operator--(void) { // pre-increment
|
||||
mpNode = mpNode->getPrev();
|
||||
return *this;
|
||||
}
|
||||
_Iter operator--(int) { // post-increment
|
||||
_Iter tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
_Node* getNode(void) const { return mpNode; }
|
||||
|
||||
private:
|
||||
_Node* mpNode;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 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<class T> class List {
|
||||
public:
|
||||
typedef _ListNode<T> _Node;
|
||||
|
||||
List(void) {
|
||||
prep();
|
||||
}
|
||||
List(const List<T>& src) { // copy-constructor
|
||||
prep();
|
||||
insert(begin(), src.begin(), src.end());
|
||||
}
|
||||
virtual ~List(void) {
|
||||
clear();
|
||||
delete[] (unsigned char*) mpMiddle;
|
||||
}
|
||||
|
||||
typedef _ListIterator<T,T&> iterator;
|
||||
typedef _ListIterator<T, const T&> const_iterator;
|
||||
|
||||
List<T>& operator=(const List<T>& right);
|
||||
|
||||
/* returns true if the list is empty */
|
||||
bool empty(void) const { return mpMiddle->getNext() == mpMiddle; }
|
||||
|
||||
/* return #of elements in list */
|
||||
unsigned int size(void) const {
|
||||
return distance(begin(), end());
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the first element or one past the last element. The
|
||||
* _ListNode* we're returning is converted to an "iterator" by a
|
||||
* constructor in _ListIterator.
|
||||
*/
|
||||
iterator begin() { return mpMiddle->getNext(); }
|
||||
const_iterator begin() const { return mpMiddle->getNext(); }
|
||||
iterator end() { return mpMiddle; }
|
||||
const_iterator end() const { return 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 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 pNext;
|
||||
}
|
||||
|
||||
/* remove a range of elements */
|
||||
iterator erase(iterator first, iterator last) {
|
||||
while (first != last)
|
||||
erase(first++); // don't erase than incr later!
|
||||
return last;
|
||||
}
|
||||
|
||||
/* remove all contents of the list */
|
||||
void clear(void) {
|
||||
_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.
|
||||
*
|
||||
* (This is actually a generic iterator function. It should be part
|
||||
* of some other class, possibly an iterator base class. It needs to
|
||||
* know the difference between a list, which has to march through,
|
||||
* and a vector, which can just do pointer math.)
|
||||
*/
|
||||
unsigned int distance(iterator first, iterator last) {
|
||||
unsigned int count = 0;
|
||||
while (first != last) {
|
||||
++first;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
unsigned int distance(const_iterator first, const_iterator last) const {
|
||||
unsigned int count = 0;
|
||||
while (first != last) {
|
||||
++first;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* I want a _ListNode 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(void) {
|
||||
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
|
33
include/utils/Log.h
Normal file
33
include/utils/Log.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#endif // _LIBS_UTILS_LOG_H
|
20
include/utils/LogSocket.h
Normal file
20
include/utils/LogSocket.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* utils/LogSocket.h
|
||||
**
|
||||
** Copyright 2008, The Android Open Source Project
|
||||
**
|
||||
** This file is dual licensed. It may be redistributed and/or modified
|
||||
** under the terms of the Apache 2.0 License OR version 2 of the GNU
|
||||
** General Public License.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_LOGSOCKET_H
|
||||
#define _UTILS_LOGSOCKET_H
|
||||
|
||||
#define SOCKET_CLOSE_LOCAL 0
|
||||
|
||||
void add_send_stats(int fd, int send);
|
||||
void add_recv_stats(int fd, int recv);
|
||||
void log_socket_close(int fd, short reason);
|
||||
void log_socket_connect(int fd, unsigned int ip, unsigned short port);
|
||||
|
||||
#endif /* _UTILS_LOGSOCKET_H */
|
51
include/utils/MemoryBase.h
Normal file
51
include/utils/MemoryBase.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 ANDROID_MEMORY_BASE_H
|
||||
#define ANDROID_MEMORY_BASE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/IMemory.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class MemoryBase : public BnMemory
|
||||
{
|
||||
public:
|
||||
MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
|
||||
virtual ~MemoryBase();
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
|
||||
|
||||
protected:
|
||||
size_t getSize() const { return mSize; }
|
||||
ssize_t getOffset() const { return mOffset; }
|
||||
const sp<IMemoryHeap>& getHeap() const { return mHeap; }
|
||||
|
||||
private:
|
||||
size_t mSize;
|
||||
ssize_t mOffset;
|
||||
sp<IMemoryHeap> mHeap;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEMORY_BASE_H
|
238
include/utils/MemoryDealer.h
Normal file
238
include/utils/MemoryDealer.h
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* 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_MEMORY_DEALER_H
|
||||
#define ANDROID_MEMORY_DEALER_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/IMemory.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/MemoryHeapBase.h>
|
||||
|
||||
namespace android {
|
||||
// ----------------------------------------------------------------------------
|
||||
class String8;
|
||||
|
||||
/*
|
||||
* interface for implementing a "heap". A heap basically provides
|
||||
* the IMemoryHeap interface for cross-process sharing and the
|
||||
* ability to map/unmap pages within the heap.
|
||||
*/
|
||||
class HeapInterface : public virtual BnMemoryHeap
|
||||
{
|
||||
public:
|
||||
// all values must be page-aligned
|
||||
virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* interface for implementing an allocator. An allocator provides
|
||||
* methods for allocating and freeing memory blocks and dumping
|
||||
* its state.
|
||||
*/
|
||||
class AllocatorInterface : public RefBase
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
PAGE_ALIGNED = 0x00000001
|
||||
};
|
||||
|
||||
virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
|
||||
virtual status_t deallocate(size_t offset) = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual void dump(const char* what, uint32_t flags = 0) const = 0;
|
||||
virtual void dump(String8& res,
|
||||
const char* what, uint32_t flags = 0) const = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* concrete implementation of HeapInterface on top of mmap()
|
||||
*/
|
||||
class SharedHeap : public HeapInterface, public MemoryHeapBase
|
||||
{
|
||||
public:
|
||||
SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
|
||||
virtual ~SharedHeap();
|
||||
virtual sp<IMemory> mapMemory(size_t offset, size_t size);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* A simple templatized doubly linked-list implementation
|
||||
*/
|
||||
|
||||
template <typename NODE>
|
||||
class LinkedList
|
||||
{
|
||||
NODE* mFirst;
|
||||
NODE* mLast;
|
||||
|
||||
public:
|
||||
LinkedList() : mFirst(0), mLast(0) { }
|
||||
bool isEmpty() const { return mFirst == 0; }
|
||||
NODE const* head() const { return mFirst; }
|
||||
NODE* head() { return mFirst; }
|
||||
NODE const* tail() const { return mLast; }
|
||||
NODE* tail() { return mLast; }
|
||||
|
||||
void insertAfter(NODE* node, NODE* newNode) {
|
||||
newNode->prev = node;
|
||||
newNode->next = node->next;
|
||||
if (node->next == 0) mLast = newNode;
|
||||
else node->next->prev = newNode;
|
||||
node->next = newNode;
|
||||
}
|
||||
|
||||
void insertBefore(NODE* node, NODE* newNode) {
|
||||
newNode->prev = node->prev;
|
||||
newNode->next = node;
|
||||
if (node->prev == 0) mFirst = newNode;
|
||||
else node->prev->next = newNode;
|
||||
node->prev = newNode;
|
||||
}
|
||||
|
||||
void insertHead(NODE* newNode) {
|
||||
if (mFirst == 0) {
|
||||
mFirst = mLast = newNode;
|
||||
newNode->prev = newNode->next = 0;
|
||||
} else {
|
||||
insertBefore(mFirst, newNode);
|
||||
}
|
||||
}
|
||||
|
||||
void insertTail(NODE* newNode) {
|
||||
if (mLast == 0) insertBeginning(newNode);
|
||||
else insertAfter(mLast, newNode);
|
||||
}
|
||||
|
||||
NODE* remove(NODE* node) {
|
||||
if (node->prev == 0) mFirst = node->next;
|
||||
else node->prev->next = node->next;
|
||||
if (node->next == 0) mLast = node->prev;
|
||||
else node->next->prev = node->prev;
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* concrete implementation of AllocatorInterface using a simple
|
||||
* best-fit allocation scheme
|
||||
*/
|
||||
class SimpleBestFitAllocator : public AllocatorInterface
|
||||
{
|
||||
public:
|
||||
|
||||
SimpleBestFitAllocator(size_t size);
|
||||
virtual ~SimpleBestFitAllocator();
|
||||
|
||||
virtual size_t allocate(size_t size, uint32_t flags = 0);
|
||||
virtual status_t deallocate(size_t offset);
|
||||
virtual size_t size() const;
|
||||
virtual void dump(const char* what, uint32_t flags = 0) const;
|
||||
virtual void dump(String8& res,
|
||||
const char* what, uint32_t flags = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
struct chunk_t {
|
||||
chunk_t(size_t start, size_t size)
|
||||
: start(start), size(size), free(1), prev(0), next(0) {
|
||||
}
|
||||
size_t start;
|
||||
size_t size : 28;
|
||||
int free : 4;
|
||||
mutable chunk_t* prev;
|
||||
mutable chunk_t* next;
|
||||
};
|
||||
|
||||
ssize_t alloc(size_t size, uint32_t flags);
|
||||
chunk_t* dealloc(size_t start);
|
||||
void dump_l(const char* what, uint32_t flags = 0) const;
|
||||
void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
|
||||
|
||||
static const int kMemoryAlign;
|
||||
mutable Mutex mLock;
|
||||
LinkedList<chunk_t> mList;
|
||||
size_t mHeapSize;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class MemoryDealer : public RefBase
|
||||
{
|
||||
public:
|
||||
|
||||
enum {
|
||||
READ_ONLY = MemoryHeapBase::READ_ONLY,
|
||||
PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
|
||||
};
|
||||
|
||||
// creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
|
||||
MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
|
||||
|
||||
// provide a custom heap but use the SimpleBestFitAllocator
|
||||
MemoryDealer(const sp<HeapInterface>& heap);
|
||||
|
||||
// provide both custom heap and allocotar
|
||||
MemoryDealer(
|
||||
const sp<HeapInterface>& heap,
|
||||
const sp<AllocatorInterface>& allocator);
|
||||
|
||||
virtual ~MemoryDealer();
|
||||
|
||||
virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
|
||||
virtual void deallocate(size_t offset);
|
||||
virtual void dump(const char* what, uint32_t flags = 0) const;
|
||||
|
||||
|
||||
sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
|
||||
sp<AllocatorInterface> getAllocator() const { return allocator(); }
|
||||
|
||||
private:
|
||||
const sp<HeapInterface>& heap() const;
|
||||
const sp<AllocatorInterface>& allocator() const;
|
||||
|
||||
class Allocation : public BnMemory {
|
||||
public:
|
||||
Allocation(const sp<MemoryDealer>& dealer,
|
||||
ssize_t offset, size_t size, const sp<IMemory>& memory);
|
||||
virtual ~Allocation();
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
|
||||
private:
|
||||
sp<MemoryDealer> mDealer;
|
||||
ssize_t mOffset;
|
||||
size_t mSize;
|
||||
sp<IMemory> mMemory;
|
||||
};
|
||||
|
||||
sp<HeapInterface> mHeap;
|
||||
sp<AllocatorInterface> mAllocator;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEMORY_DEALER_H
|
98
include/utils/MemoryHeapBase.h
Normal file
98
include/utils/MemoryHeapBase.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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 ANDROID_MEMORY_HEAP_BASE_H
|
||||
#define ANDROID_MEMORY_HEAP_BASE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/IMemory.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class MemoryHeapBase : public virtual BnMemoryHeap
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
READ_ONLY = IMemoryHeap::READ_ONLY,
|
||||
MAP_ONCE = IMemoryHeap::MAP_ONCE,
|
||||
// memory won't be mapped locally, but will be mapped in the remote
|
||||
// process.
|
||||
DONT_MAP_LOCALLY = 0x00000100
|
||||
};
|
||||
|
||||
/*
|
||||
* maps the memory referenced by fd. but DOESN'T take ownership
|
||||
* of the filedescriptor (it makes a copy with dup()
|
||||
*/
|
||||
MemoryHeapBase(int fd, size_t size, uint32_t flags = 0);
|
||||
|
||||
/*
|
||||
* maps memory from the given device
|
||||
*/
|
||||
MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
|
||||
|
||||
/*
|
||||
* maps memory from ashmem, with the given name for debugging
|
||||
*/
|
||||
MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
|
||||
|
||||
virtual ~MemoryHeapBase();
|
||||
|
||||
/* implement IMemoryHeap interface */
|
||||
virtual int getHeapID() const;
|
||||
virtual void* getBase() const;
|
||||
virtual size_t getSize() const;
|
||||
virtual uint32_t getFlags() const;
|
||||
|
||||
const char* getDevice() const;
|
||||
|
||||
/* this closes this heap -- use carefully */
|
||||
void dispose();
|
||||
|
||||
/* this is only needed as a workaround, use only if you know
|
||||
* what you are doing */
|
||||
status_t setDevice(const char* device) {
|
||||
if (mDevice == 0)
|
||||
mDevice = device;
|
||||
return mDevice ? NO_ERROR : ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
protected:
|
||||
MemoryHeapBase();
|
||||
// init() takes ownership of fd
|
||||
status_t init(int fd, void *base, int size,
|
||||
int flags = 0, const char* device = NULL);
|
||||
|
||||
private:
|
||||
status_t mapfd(int fd, size_t size);
|
||||
|
||||
int mFD;
|
||||
size_t mSize;
|
||||
void* mBase;
|
||||
uint32_t mFlags;
|
||||
const char* mDevice;
|
||||
bool mNeedUnmap;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEMORY_HEAP_BASE_H
|
80
include/utils/MemoryHeapPmem.h
Normal file
80
include/utils/MemoryHeapPmem.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 ANDROID_MEMORY_HEAP_PMEM_H
|
||||
#define ANDROID_MEMORY_HEAP_PMEM_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/MemoryDealer.h>
|
||||
#include <utils/MemoryHeapBase.h>
|
||||
#include <utils/IMemory.h>
|
||||
#include <utils/SortedVector.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class MemoryHeapBase;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
|
||||
{
|
||||
public:
|
||||
class MemoryPmem : public BnMemory {
|
||||
public:
|
||||
MemoryPmem(const sp<MemoryHeapPmem>& heap);
|
||||
~MemoryPmem();
|
||||
protected:
|
||||
const sp<MemoryHeapPmem>& getHeap() const { return mClientHeap; }
|
||||
private:
|
||||
friend class MemoryHeapPmem;
|
||||
virtual void revoke() = 0;
|
||||
sp<MemoryHeapPmem> mClientHeap;
|
||||
};
|
||||
|
||||
MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
|
||||
uint32_t flags = IMemoryHeap::MAP_ONCE);
|
||||
~MemoryHeapPmem();
|
||||
|
||||
/* HeapInterface additions */
|
||||
virtual sp<IMemory> mapMemory(size_t offset, size_t size);
|
||||
|
||||
/* make the whole heap visible (you know who you are) */
|
||||
virtual status_t slap();
|
||||
|
||||
/* hide (revoke) the whole heap (the client will see the garbage page) */
|
||||
virtual status_t unslap();
|
||||
|
||||
/* revoke all allocations made by this heap */
|
||||
virtual void revoke();
|
||||
|
||||
private:
|
||||
/* use this to create your own IMemory for mapMemory */
|
||||
virtual sp<MemoryPmem> createMemory(size_t offset, size_t size);
|
||||
void remove(const wp<MemoryPmem>& memory);
|
||||
|
||||
private:
|
||||
sp<MemoryHeapBase> mParentHeap;
|
||||
mutable Mutex mLock;
|
||||
SortedVector< wp<MemoryPmem> > mAllocations;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEMORY_HEAP_PMEM_H
|
209
include/utils/Parcel.h
Normal file
209
include/utils/Parcel.h
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* 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_PARCEL_H
|
||||
#define ANDROID_PARCEL_H
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class IBinder;
|
||||
class ProcessState;
|
||||
class String8;
|
||||
class TextOutput;
|
||||
|
||||
struct flat_binder_object; // defined in support_p/binder_module.h
|
||||
|
||||
class Parcel
|
||||
{
|
||||
public:
|
||||
Parcel();
|
||||
~Parcel();
|
||||
|
||||
const uint8_t* data() const;
|
||||
size_t dataSize() const;
|
||||
size_t dataAvail() const;
|
||||
size_t dataPosition() const;
|
||||
size_t dataCapacity() const;
|
||||
|
||||
status_t setDataSize(size_t size);
|
||||
void setDataPosition(size_t pos) const;
|
||||
status_t setDataCapacity(size_t size);
|
||||
|
||||
status_t setData(const uint8_t* buffer, size_t len);
|
||||
|
||||
status_t appendFrom(Parcel *parcel, size_t start, size_t len);
|
||||
|
||||
bool hasFileDescriptors() const;
|
||||
|
||||
status_t writeInterfaceToken(const String16& interface);
|
||||
bool enforceInterface(const String16& interface) const;
|
||||
|
||||
void freeData();
|
||||
|
||||
const size_t* objects() const;
|
||||
size_t objectsCount() const;
|
||||
|
||||
status_t errorCheck() const;
|
||||
void setError(status_t err);
|
||||
|
||||
status_t write(const void* data, size_t len);
|
||||
void* writeInplace(size_t len);
|
||||
status_t writeUnpadded(const void* data, size_t len);
|
||||
status_t writeInt32(int32_t val);
|
||||
status_t writeInt64(int64_t val);
|
||||
status_t writeFloat(float val);
|
||||
status_t writeDouble(double val);
|
||||
status_t writeCString(const char* str);
|
||||
status_t writeString8(const String8& str);
|
||||
status_t writeString16(const String16& str);
|
||||
status_t writeString16(const char16_t* str, size_t len);
|
||||
status_t writeStrongBinder(const sp<IBinder>& val);
|
||||
status_t writeWeakBinder(const wp<IBinder>& val);
|
||||
|
||||
// doesn't take ownership of the native_handle
|
||||
status_t writeNativeHandle(const native_handle& handle);
|
||||
|
||||
// Place a file descriptor into the parcel. The given fd must remain
|
||||
// valid for the lifetime of the parcel.
|
||||
status_t writeFileDescriptor(int fd);
|
||||
|
||||
// Place a file descriptor into the parcel. A dup of the fd is made, which
|
||||
// will be closed once the parcel is destroyed.
|
||||
status_t writeDupFileDescriptor(int fd);
|
||||
|
||||
status_t writeObject(const flat_binder_object& val, bool nullMetaData);
|
||||
|
||||
void remove(size_t start, size_t amt);
|
||||
|
||||
status_t read(void* outData, size_t len) const;
|
||||
const void* readInplace(size_t len) const;
|
||||
int32_t readInt32() const;
|
||||
status_t readInt32(int32_t *pArg) const;
|
||||
int64_t readInt64() const;
|
||||
status_t readInt64(int64_t *pArg) const;
|
||||
float readFloat() const;
|
||||
status_t readFloat(float *pArg) const;
|
||||
double readDouble() const;
|
||||
status_t readDouble(double *pArg) const;
|
||||
|
||||
const char* readCString() const;
|
||||
String8 readString8() const;
|
||||
String16 readString16() const;
|
||||
const char16_t* readString16Inplace(size_t* outLen) const;
|
||||
sp<IBinder> readStrongBinder() const;
|
||||
wp<IBinder> readWeakBinder() const;
|
||||
|
||||
|
||||
// if alloc is NULL, native_handle is allocated with malloc(), otherwise
|
||||
// alloc is used. If the function fails, the effects of alloc() must be
|
||||
// reverted by the caller.
|
||||
native_handle* readNativeHandle(
|
||||
native_handle* (*alloc)(void* cookie, int numFds, int ints),
|
||||
void* cookie) const;
|
||||
|
||||
|
||||
// Retrieve a file descriptor from the parcel. This returns the raw fd
|
||||
// in the parcel, which you do not own -- use dup() to get your own copy.
|
||||
int readFileDescriptor() const;
|
||||
|
||||
const flat_binder_object* readObject(bool nullMetaData) const;
|
||||
|
||||
// Explicitly close all file descriptors in the parcel.
|
||||
void closeFileDescriptors();
|
||||
|
||||
typedef void (*release_func)(Parcel* parcel,
|
||||
const uint8_t* data, size_t dataSize,
|
||||
const size_t* objects, size_t objectsSize,
|
||||
void* cookie);
|
||||
|
||||
const uint8_t* ipcData() const;
|
||||
size_t ipcDataSize() const;
|
||||
const size_t* ipcObjects() const;
|
||||
size_t ipcObjectsCount() const;
|
||||
void ipcSetDataReference(const uint8_t* data, size_t dataSize,
|
||||
const size_t* objects, size_t objectsCount,
|
||||
release_func relFunc, void* relCookie);
|
||||
|
||||
void print(TextOutput& to, uint32_t flags = 0) const;
|
||||
|
||||
private:
|
||||
Parcel(const Parcel& o);
|
||||
Parcel& operator=(const Parcel& o);
|
||||
|
||||
status_t finishWrite(size_t len);
|
||||
void releaseObjects();
|
||||
void acquireObjects();
|
||||
status_t growData(size_t len);
|
||||
status_t restartWrite(size_t desired);
|
||||
status_t continueWrite(size_t desired);
|
||||
void freeDataNoInit();
|
||||
void initState();
|
||||
void scanForFds() const;
|
||||
|
||||
status_t mError;
|
||||
uint8_t* mData;
|
||||
size_t mDataSize;
|
||||
size_t mDataCapacity;
|
||||
mutable size_t mDataPos;
|
||||
size_t* mObjects;
|
||||
size_t mObjectsSize;
|
||||
size_t mObjectsCapacity;
|
||||
mutable size_t mNextObjectHint;
|
||||
|
||||
mutable bool mFdsKnown;
|
||||
mutable bool mHasFds;
|
||||
|
||||
release_func mOwner;
|
||||
void* mOwnerCookie;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
|
||||
{
|
||||
parcel.print(to);
|
||||
return to;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Generic acquire and release of objects.
|
||||
void acquire_object(const sp<ProcessState>& proc,
|
||||
const flat_binder_object& obj, const void* who);
|
||||
void release_object(const sp<ProcessState>& proc,
|
||||
const flat_binder_object& obj, const void* who);
|
||||
|
||||
void flatten_binder(const sp<ProcessState>& proc,
|
||||
const sp<IBinder>& binder, flat_binder_object* out);
|
||||
void flatten_binder(const sp<ProcessState>& proc,
|
||||
const wp<IBinder>& binder, flat_binder_object* out);
|
||||
status_t unflatten_binder(const sp<ProcessState>& proc,
|
||||
const flat_binder_object& flat, sp<IBinder>* out);
|
||||
status_t unflatten_binder(const sp<ProcessState>& proc,
|
||||
const flat_binder_object& flat, wp<IBinder>* out);
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_PARCEL_H
|
108
include/utils/Pipe.h
Normal file
108
include/utils/Pipe.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// FIFO I/O.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_PIPE_H
|
||||
#define _LIBS_UTILS_PIPE_H
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
#error DO NOT USE THIS FILE IN THE DEVICE BUILD
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Simple anonymous unidirectional pipe.
|
||||
*
|
||||
* The primary goal is to create an implementation with minimal overhead
|
||||
* under Linux. Making Windows, Mac OS X, and Linux all work the same way
|
||||
* is a secondary goal. Part of this goal is to have something that can
|
||||
* be fed to a select() call, so that the application can sleep in the
|
||||
* kernel until something interesting happens.
|
||||
*/
|
||||
class Pipe {
|
||||
public:
|
||||
Pipe(void);
|
||||
virtual ~Pipe(void);
|
||||
|
||||
/* Create the pipe */
|
||||
bool create(void);
|
||||
|
||||
/* Create a read-only pipe, using the supplied handle as read handle */
|
||||
bool createReader(unsigned long handle);
|
||||
/* Create a write-only pipe, using the supplied handle as write handle */
|
||||
bool createWriter(unsigned long handle);
|
||||
|
||||
/* Is this object ready to go? */
|
||||
bool isCreated(void);
|
||||
|
||||
/*
|
||||
* Read "count" bytes from the pipe. Returns the amount of data read,
|
||||
* or 0 if no data available and we're non-blocking.
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
int read(void* buf, int count);
|
||||
|
||||
/*
|
||||
* Write "count" bytes into the pipe. Returns number of bytes written,
|
||||
* or 0 if there's no room for more data and we're non-blocking.
|
||||
* Returns -1 on error.
|
||||
*/
|
||||
int write(const void* buf, int count);
|
||||
|
||||
/* Returns "true" if data is available to read */
|
||||
bool readReady(void);
|
||||
|
||||
/* Enable or disable non-blocking I/O for reads */
|
||||
bool setReadNonBlocking(bool val);
|
||||
/* Enable or disable non-blocking I/O for writes. Only works on Linux. */
|
||||
bool setWriteNonBlocking(bool val);
|
||||
|
||||
/*
|
||||
* Get the handle. Only useful in some platform-specific situations.
|
||||
*/
|
||||
unsigned long getReadHandle(void);
|
||||
unsigned long getWriteHandle(void);
|
||||
|
||||
/*
|
||||
* Modify inheritance, i.e. whether or not a child process will get
|
||||
* copies of the descriptors. Systems with fork+exec allow us to close
|
||||
* the descriptors before launching the child process, but Win32
|
||||
* doesn't allow it.
|
||||
*/
|
||||
bool disallowReadInherit(void);
|
||||
bool disallowWriteInherit(void);
|
||||
|
||||
/*
|
||||
* Close one side or the other. Useful in the parent after launching
|
||||
* a child process.
|
||||
*/
|
||||
bool closeRead(void);
|
||||
bool closeWrite(void);
|
||||
|
||||
private:
|
||||
bool mReadNonBlocking;
|
||||
bool mWriteNonBlocking;
|
||||
|
||||
unsigned long mReadHandle;
|
||||
unsigned long mWriteHandle;
|
||||
};
|
||||
|
||||
}; // android
|
||||
|
||||
#endif // _LIBS_UTILS_PIPE_H
|
117
include/utils/ProcessState.h
Normal file
117
include/utils/ProcessState.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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_PROCESS_STATE_H
|
||||
#define ANDROID_PROCESS_STATE_H
|
||||
|
||||
#include <utils/IBinder.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/String16.h>
|
||||
|
||||
#include <utils/threads.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
// Global variables
|
||||
extern int mArgC;
|
||||
extern const char* const* mArgV;
|
||||
extern int mArgLen;
|
||||
|
||||
class IPCThreadState;
|
||||
|
||||
class ProcessState : public virtual RefBase
|
||||
{
|
||||
public:
|
||||
static sp<ProcessState> self();
|
||||
|
||||
static void setSingleProcess(bool singleProcess);
|
||||
|
||||
void setContextObject(const sp<IBinder>& object);
|
||||
sp<IBinder> getContextObject(const sp<IBinder>& caller);
|
||||
|
||||
void setContextObject(const sp<IBinder>& object,
|
||||
const String16& name);
|
||||
sp<IBinder> getContextObject(const String16& name,
|
||||
const sp<IBinder>& caller);
|
||||
|
||||
bool supportsProcesses() const;
|
||||
|
||||
void startThreadPool();
|
||||
|
||||
typedef bool (*context_check_func)(const String16& name,
|
||||
const sp<IBinder>& caller,
|
||||
void* userData);
|
||||
|
||||
bool isContextManager(void) const;
|
||||
bool becomeContextManager(
|
||||
context_check_func checkFunc,
|
||||
void* userData);
|
||||
|
||||
sp<IBinder> getStrongProxyForHandle(int32_t handle);
|
||||
wp<IBinder> getWeakProxyForHandle(int32_t handle);
|
||||
void expungeHandle(int32_t handle, IBinder* binder);
|
||||
|
||||
void setArgs(int argc, const char* const argv[]);
|
||||
int getArgC() const;
|
||||
const char* const* getArgV() const;
|
||||
|
||||
void setArgV0(const char* txt);
|
||||
|
||||
void spawnPooledThread(bool isMain);
|
||||
|
||||
private:
|
||||
friend class IPCThreadState;
|
||||
|
||||
ProcessState();
|
||||
~ProcessState();
|
||||
|
||||
ProcessState(const ProcessState& o);
|
||||
ProcessState& operator=(const ProcessState& o);
|
||||
|
||||
struct handle_entry {
|
||||
IBinder* binder;
|
||||
RefBase::weakref_type* refs;
|
||||
};
|
||||
|
||||
handle_entry* lookupHandleLocked(int32_t handle);
|
||||
|
||||
int mDriverFD;
|
||||
void* mVMStart;
|
||||
|
||||
mutable Mutex mLock; // protects everything below.
|
||||
|
||||
Vector<handle_entry>mHandleToObject;
|
||||
|
||||
bool mManagesContexts;
|
||||
context_check_func mBinderContextCheckFunc;
|
||||
void* mBinderContextUserData;
|
||||
|
||||
KeyedVector<String16, sp<IBinder> >
|
||||
mContexts;
|
||||
|
||||
|
||||
String8 mRootDir;
|
||||
bool mThreadPoolStarted;
|
||||
volatile int32_t mThreadPoolSeq;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_PROCESS_STATE_H
|
550
include/utils/RefBase.h
Normal file
550
include/utils/RefBase.h
Normal file
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
* 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 <utils/TextOutput.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
template<typename T> class wp;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define COMPARE(_op_) \
|
||||
inline bool operator _op_ (const sp<T>& o) const { \
|
||||
return m_ptr _op_ o.m_ptr; \
|
||||
} \
|
||||
inline bool operator _op_ (const wp<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 wp<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 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);
|
||||
|
||||
bool attemptIncStrong(const void* id);
|
||||
|
||||
//! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
|
||||
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);
|
||||
}
|
||||
|
||||
protected:
|
||||
RefBase();
|
||||
virtual ~RefBase();
|
||||
|
||||
//! Flags for extendObjectLifetime()
|
||||
enum {
|
||||
OBJECT_LIFETIME_WEAK = 0x0001,
|
||||
OBJECT_LIFETIME_FOREVER = 0x0003
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
weakref_impl* const mRefs;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template <class T>
|
||||
class LightRefBase
|
||||
{
|
||||
public:
|
||||
inline LightRefBase() : mCount(0) { }
|
||||
inline void incStrong(const void* id) const {
|
||||
android_atomic_inc(&mCount);
|
||||
}
|
||||
inline void decStrong(const void* id) const {
|
||||
if (android_atomic_dec(&mCount) == 1) {
|
||||
delete static_cast<const T*>(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
inline ~LightRefBase() { }
|
||||
|
||||
private:
|
||||
mutable volatile int32_t mCount;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class sp
|
||||
{
|
||||
public:
|
||||
typedef typename RefBase::weakref_type weakref_type;
|
||||
|
||||
inline sp() : m_ptr(0) { }
|
||||
|
||||
sp(T* other);
|
||||
sp(const sp<T>& other);
|
||||
template<typename U> sp(U* other);
|
||||
template<typename U> sp(const sp<U>& other);
|
||||
|
||||
~sp();
|
||||
|
||||
// Assignment
|
||||
|
||||
sp& operator = (T* other);
|
||||
sp& operator = (const sp<T>& other);
|
||||
|
||||
template<typename U> sp& operator = (const sp<U>& other);
|
||||
template<typename U> sp& operator = (U* other);
|
||||
|
||||
//! Special optimization for use by ProcessState (and nobody else).
|
||||
void force_set(T* other);
|
||||
|
||||
// Reset
|
||||
|
||||
void clear();
|
||||
|
||||
// Accessors
|
||||
|
||||
inline T& operator* () const { return *m_ptr; }
|
||||
inline T* operator-> () const { return m_ptr; }
|
||||
inline T* get() const { return m_ptr; }
|
||||
|
||||
// Operators
|
||||
|
||||
COMPARE(==)
|
||||
COMPARE(!=)
|
||||
COMPARE(>)
|
||||
COMPARE(<)
|
||||
COMPARE(<=)
|
||||
COMPARE(>=)
|
||||
|
||||
private:
|
||||
template<typename Y> friend class sp;
|
||||
template<typename Y> friend class wp;
|
||||
|
||||
// Optimization for wp::promote().
|
||||
sp(T* p, weakref_type* refs);
|
||||
|
||||
T* m_ptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
TextOutput& operator<<(TextOutput& to, const sp<T>& val);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
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(==)
|
||||
COMPARE(!=)
|
||||
COMPARE(>)
|
||||
COMPARE(<)
|
||||
COMPARE(<=)
|
||||
COMPARE(>=)
|
||||
|
||||
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
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user serviceable parts below here.
|
||||
|
||||
template<typename T>
|
||||
sp<T>::sp(T* other)
|
||||
: m_ptr(other)
|
||||
{
|
||||
if (other) other->incStrong(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>::sp(const sp<T>& other)
|
||||
: m_ptr(other.m_ptr)
|
||||
{
|
||||
if (m_ptr) m_ptr->incStrong(this);
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>::sp(U* other) : m_ptr(other)
|
||||
{
|
||||
if (other) other->incStrong(this);
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>::sp(const sp<U>& other)
|
||||
: m_ptr(other.m_ptr)
|
||||
{
|
||||
if (m_ptr) m_ptr->incStrong(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>::~sp()
|
||||
{
|
||||
if (m_ptr) m_ptr->decStrong(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>& sp<T>::operator = (const sp<T>& other) {
|
||||
if (other.m_ptr) other.m_ptr->incStrong(this);
|
||||
if (m_ptr) m_ptr->decStrong(this);
|
||||
m_ptr = other.m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>& sp<T>::operator = (T* other)
|
||||
{
|
||||
if (other) other->incStrong(this);
|
||||
if (m_ptr) m_ptr->decStrong(this);
|
||||
m_ptr = other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>& sp<T>::operator = (const sp<U>& other)
|
||||
{
|
||||
if (other.m_ptr) other.m_ptr->incStrong(this);
|
||||
if (m_ptr) m_ptr->decStrong(this);
|
||||
m_ptr = other.m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> template<typename U>
|
||||
sp<T>& sp<T>::operator = (U* other)
|
||||
{
|
||||
if (other) other->incStrong(this);
|
||||
if (m_ptr) m_ptr->decStrong(this);
|
||||
m_ptr = other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sp<T>::force_set(T* other)
|
||||
{
|
||||
other->forceIncStrong(this);
|
||||
m_ptr = other;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sp<T>::clear()
|
||||
{
|
||||
if (m_ptr) {
|
||||
m_ptr->decStrong(this);
|
||||
m_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
sp<T>::sp(T* p, weakref_type* refs)
|
||||
: m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
|
||||
{
|
||||
to << "sp<>(" << val.get() << ")";
|
||||
return to;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
{
|
||||
if (other.m_ptr) other.m_refs->incWeak(this);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other.m_ptr;
|
||||
m_refs = other.m_refs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
wp<T>& wp<T>::operator = (const sp<T>& other)
|
||||
{
|
||||
weakref_type* newRefs =
|
||||
other != NULL ? other->createWeak(this) : 0;
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other.get();
|
||||
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)
|
||||
{
|
||||
if (other.m_ptr) other.m_refs->incWeak(this);
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other.m_ptr;
|
||||
m_refs = other.m_refs;
|
||||
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;
|
||||
if (m_ptr) m_refs->decWeak(this);
|
||||
m_ptr = other.get();
|
||||
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
|
||||
{
|
||||
return sp<T>(m_ptr, m_refs);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
to << "wp<>(" << val.unsafe_get() << ")";
|
||||
return to;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_REF_BASE_H
|
1720
include/utils/ResourceTypes.h
Normal file
1720
include/utils/ResourceTypes.h
Normal file
File diff suppressed because it is too large
Load diff
146
include/utils/SharedBuffer.h
Normal file
146
include/utils/SharedBuffer.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
//! get the SharedBuffer from the data pointer
|
||||
static inline const SharedBuffer* sharedBuffer(const void* data);
|
||||
|
||||
//! 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() { }
|
||||
inline SharedBuffer(const SharedBuffer&);
|
||||
|
||||
// 16 bytes. must be sized to preserve correct alingment.
|
||||
mutable int32_t mRefs;
|
||||
size_t mSize;
|
||||
uint32_t mReserved[2];
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
|
||||
return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
|
||||
}
|
||||
|
||||
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 ((SharedBuffer*)data)-1;
|
||||
}
|
||||
|
||||
const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
|
||||
{
|
||||
return ((const SharedBuffer*)data)-1;
|
||||
}
|
||||
|
||||
size_t SharedBuffer::sizeFromData(const void* data)
|
||||
{
|
||||
return (((const SharedBuffer*)data)-1)->mSize;
|
||||
}
|
||||
|
||||
bool SharedBuffer::onlyOwner() const {
|
||||
return (mRefs == 1);
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_VECTOR_H
|
80
include/utils/Socket.h
Normal file
80
include/utils/Socket.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Socket class. Modeled after Java classes.
|
||||
//
|
||||
#ifndef _RUNTIME_SOCKET_H
|
||||
#define _RUNTIME_SOCKET_H
|
||||
|
||||
#include <utils/inet_address.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Basic socket class, needed to abstract away the differences between
|
||||
* BSD sockets and WinSock. This establishes a streaming network
|
||||
* connection (TCP/IP) to somebody.
|
||||
*/
|
||||
class Socket {
|
||||
public:
|
||||
Socket(void);
|
||||
~Socket(void);
|
||||
|
||||
// Create a connection to somewhere.
|
||||
// Return 0 on success.
|
||||
int connect(const char* host, int port);
|
||||
int connect(const InetAddress* addr, int port);
|
||||
|
||||
|
||||
// Close the socket. Don't try to use this object again after
|
||||
// calling this. Returns false on failure.
|
||||
bool close(void);
|
||||
|
||||
// If we created the socket without an address, we can use these
|
||||
// to finish the connection. Returns 0 on success.
|
||||
int bind(const SocketAddress& bindPoint);
|
||||
int connect(const SocketAddress& endPoint);
|
||||
|
||||
// Here we deviate from the traditional object-oriented fanciness
|
||||
// and just provide read/write operators instead of getters for
|
||||
// objects that abstract a stream.
|
||||
//
|
||||
// Standard read/write semantics.
|
||||
int read(void* buf, ssize_t len) const;
|
||||
int write(const void* buf, ssize_t len) const;
|
||||
|
||||
// This must be called once, at program startup.
|
||||
static bool bootInit(void);
|
||||
static void finalShutdown(void);
|
||||
|
||||
private:
|
||||
// Internal function that establishes a connection.
|
||||
int doConnect(const InetSocketAddress& addr);
|
||||
|
||||
unsigned long mSock; // holds SOCKET or int
|
||||
|
||||
static bool mBootInitialized;
|
||||
};
|
||||
|
||||
|
||||
// debug -- unit tests
|
||||
void TestSockets(void);
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // _RUNTIME_SOCKET_H
|
282
include/utils/SortedVector.h
Normal file
282
include/utils/SortedVector.h
Normal file
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* 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_SORTED_VECTOR_H
|
||||
#define ANDROID_SORTED_VECTOR_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/VectorImpl.h>
|
||||
#include <utils/TypeHelpers.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
template <class TYPE>
|
||||
class SortedVector : private SortedVectorImpl
|
||||
{
|
||||
public:
|
||||
typedef TYPE value_type;
|
||||
|
||||
/*!
|
||||
* Constructors and destructors
|
||||
*/
|
||||
|
||||
SortedVector();
|
||||
SortedVector(const SortedVector<TYPE>& rhs);
|
||||
virtual ~SortedVector();
|
||||
|
||||
/*! copy operator */
|
||||
const SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
|
||||
SortedVector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
|
||||
|
||||
/*
|
||||
* empty the vector
|
||||
*/
|
||||
|
||||
inline void clear() { VectorImpl::clear(); }
|
||||
|
||||
/*!
|
||||
* vector stats
|
||||
*/
|
||||
|
||||
//! returns number of items in the vector
|
||||
inline size_t size() const { return VectorImpl::size(); }
|
||||
//! returns wether or not the vector is empty
|
||||
inline bool isEmpty() const { return VectorImpl::isEmpty(); }
|
||||
//! returns how many items can be stored without reallocating the backing store
|
||||
inline size_t capacity() const { return VectorImpl::capacity(); }
|
||||
//! setst the capacity. capacity can never be reduced less than size()
|
||||
inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
|
||||
|
||||
/*!
|
||||
* C-style array access
|
||||
*/
|
||||
|
||||
//! read-only C-style access
|
||||
inline const TYPE* array() const;
|
||||
|
||||
//! read-write C-style access. BE VERY CAREFUL when modifying the array
|
||||
//! you ust keep it sorted! You usually don't use this function.
|
||||
TYPE* editArray();
|
||||
|
||||
//! finds the index of an item
|
||||
ssize_t indexOf(const TYPE& item) const;
|
||||
|
||||
//! finds where this item should be inserted
|
||||
size_t orderOf(const TYPE& item) const;
|
||||
|
||||
|
||||
/*!
|
||||
* accessors
|
||||
*/
|
||||
|
||||
//! read-only access to an item at a given index
|
||||
inline const TYPE& operator [] (size_t index) const;
|
||||
//! alternate name for operator []
|
||||
inline const TYPE& itemAt(size_t index) const;
|
||||
//! stack-usage of the vector. returns the top of the stack (last element)
|
||||
const TYPE& top() const;
|
||||
//! same as operator [], but allows to access the vector backward (from the end) with a negative index
|
||||
const TYPE& mirrorItemAt(ssize_t index) const;
|
||||
|
||||
/*!
|
||||
* modifing the array
|
||||
*/
|
||||
|
||||
//! add an item in the right place (and replace the one that is there)
|
||||
ssize_t add(const TYPE& item);
|
||||
|
||||
//! editItemAt() MUST NOT change the order of this item
|
||||
TYPE& editItemAt(size_t index) {
|
||||
return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
|
||||
}
|
||||
|
||||
//! merges a vector into this one
|
||||
ssize_t merge(const Vector<TYPE>& vector);
|
||||
ssize_t merge(const SortedVector<TYPE>& vector);
|
||||
|
||||
//! removes an item
|
||||
ssize_t remove(const TYPE&);
|
||||
|
||||
//! remove several items
|
||||
inline ssize_t removeItemsAt(size_t index, size_t count = 1);
|
||||
//! remove one item
|
||||
inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
|
||||
|
||||
protected:
|
||||
virtual void do_construct(void* storage, size_t num) const;
|
||||
virtual void do_destroy(void* storage, size_t num) const;
|
||||
virtual void do_copy(void* dest, const void* from, size_t num) const;
|
||||
virtual void do_splat(void* dest, const void* item, size_t num) const;
|
||||
virtual void do_move_forward(void* dest, const void* from, size_t num) const;
|
||||
virtual void do_move_backward(void* dest, const void* from, size_t num) const;
|
||||
virtual int do_compare(const void* lhs, const void* rhs) const;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user serviceable parts from here...
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<class TYPE> inline
|
||||
SortedVector<TYPE>::SortedVector()
|
||||
: SortedVectorImpl(sizeof(TYPE),
|
||||
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|
||||
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
|
||||
|(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
|
||||
|(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
SortedVector<TYPE>::SortedVector(const SortedVector<TYPE>& rhs)
|
||||
: SortedVectorImpl(rhs) {
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
SortedVector<TYPE>::~SortedVector() {
|
||||
finish_vector();
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
|
||||
SortedVectorImpl::operator = (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
|
||||
SortedVectorImpl::operator = (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE* SortedVector<TYPE>::array() const {
|
||||
return static_cast<const TYPE *>(arrayImpl());
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
TYPE* SortedVector<TYPE>::editArray() {
|
||||
return static_cast<TYPE *>(editArrayImpl());
|
||||
}
|
||||
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& SortedVector<TYPE>::operator[](size_t index) const {
|
||||
assert( index<size() );
|
||||
return *(array() + index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& SortedVector<TYPE>::itemAt(size_t index) const {
|
||||
return operator[](index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const {
|
||||
assert( (index>0 ? index : -index)<size() );
|
||||
return *(array() + ((index<0) ? (size()-index) : index));
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& SortedVector<TYPE>::top() const {
|
||||
return *(array() + size() - 1);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t SortedVector<TYPE>::add(const TYPE& item) {
|
||||
return SortedVectorImpl::add(&item);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t SortedVector<TYPE>::indexOf(const TYPE& item) const {
|
||||
return SortedVectorImpl::indexOf(&item);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
size_t SortedVector<TYPE>::orderOf(const TYPE& item) const {
|
||||
return SortedVectorImpl::orderOf(&item);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t SortedVector<TYPE>::merge(const Vector<TYPE>& vector) {
|
||||
return SortedVectorImpl::merge(reinterpret_cast<const VectorImpl&>(vector));
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t SortedVector<TYPE>::merge(const SortedVector<TYPE>& vector) {
|
||||
return SortedVectorImpl::merge(reinterpret_cast<const SortedVectorImpl&>(vector));
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t SortedVector<TYPE>::remove(const TYPE& item) {
|
||||
return SortedVectorImpl::remove(&item);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) {
|
||||
return VectorImpl::removeItemsAt(index, count);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<class TYPE>
|
||||
void SortedVector<TYPE>::do_construct(void* storage, size_t num) const {
|
||||
construct_type( reinterpret_cast<TYPE*>(storage), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const {
|
||||
destroy_type( reinterpret_cast<TYPE*>(storage), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
|
||||
copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
|
||||
splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
|
||||
move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
|
||||
move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
int SortedVector<TYPE>::do_compare(const void* lhs, const void* rhs) const {
|
||||
return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_SORTED_VECTOR_H
|
62
include/utils/StopWatch.h
Normal file
62
include/utils/StopWatch.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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_STOPWATCH_H
|
||||
#define ANDROID_STOPWATCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Timers.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
class StopWatch
|
||||
{
|
||||
public:
|
||||
StopWatch( const char *name,
|
||||
int clock = SYSTEM_TIME_MONOTONIC,
|
||||
uint32_t flags = 0);
|
||||
~StopWatch();
|
||||
|
||||
const char* name() const;
|
||||
nsecs_t lap();
|
||||
nsecs_t elapsedTime() const;
|
||||
|
||||
private:
|
||||
const char* mName;
|
||||
int mClock;
|
||||
uint32_t mFlags;
|
||||
|
||||
struct lap_t {
|
||||
nsecs_t soFar;
|
||||
nsecs_t thisLap;
|
||||
};
|
||||
|
||||
nsecs_t mStartTime;
|
||||
lap_t mLaps[8];
|
||||
int mNumLaps;
|
||||
};
|
||||
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_STOPWATCH_H
|
260
include/utils/String16.h
Normal file
260
include/utils/String16.h
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* 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_STRING16_H
|
||||
#define ANDROID_STRING16_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/SharedBuffer.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef uint16_t char16_t;
|
||||
|
||||
// Standard string functions on char16 strings.
|
||||
int strcmp16(const char16_t *, const char16_t *);
|
||||
int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
|
||||
size_t strlen16(const char16_t *);
|
||||
size_t strnlen16(const char16_t *, size_t);
|
||||
char16_t *strcpy16(char16_t *, const char16_t *);
|
||||
char16_t *strncpy16(char16_t *, const char16_t *, size_t);
|
||||
|
||||
// Version of comparison that supports embedded nulls.
|
||||
// This is different than strncmp() because we don't stop
|
||||
// at a nul character and consider the strings to be different
|
||||
// if the lengths are different (thus we need to supply the
|
||||
// lengths of both strings). This can also be used when
|
||||
// your string is not nul-terminated as it will have the
|
||||
// equivalent result as strcmp16 (unlike strncmp16).
|
||||
int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
|
||||
|
||||
// Version of strzcmp16 for comparing strings in different endianness.
|
||||
int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
class String8;
|
||||
class TextOutput;
|
||||
|
||||
//! This is a string holding UTF-16 characters.
|
||||
class String16
|
||||
{
|
||||
public:
|
||||
String16();
|
||||
String16(const String16& o);
|
||||
String16(const String16& o,
|
||||
size_t len,
|
||||
size_t begin=0);
|
||||
explicit String16(const char16_t* o);
|
||||
explicit String16(const char16_t* o, size_t len);
|
||||
explicit String16(const String8& o);
|
||||
explicit String16(const char* o);
|
||||
explicit String16(const char* o, size_t len);
|
||||
|
||||
~String16();
|
||||
|
||||
inline const char16_t* string() const;
|
||||
inline size_t size() const;
|
||||
|
||||
inline const SharedBuffer* sharedBuffer() const;
|
||||
|
||||
void setTo(const String16& other);
|
||||
status_t setTo(const char16_t* other);
|
||||
status_t setTo(const char16_t* other, size_t len);
|
||||
status_t setTo(const String16& other,
|
||||
size_t len,
|
||||
size_t begin=0);
|
||||
|
||||
status_t append(const String16& other);
|
||||
status_t append(const char16_t* other, size_t len);
|
||||
|
||||
inline String16& operator=(const String16& other);
|
||||
|
||||
inline String16& operator+=(const String16& other);
|
||||
inline String16 operator+(const String16& other) const;
|
||||
|
||||
status_t insert(size_t pos, const char16_t* chrs);
|
||||
status_t insert(size_t pos,
|
||||
const char16_t* chrs, size_t len);
|
||||
|
||||
ssize_t findFirst(char16_t c) const;
|
||||
ssize_t findLast(char16_t c) const;
|
||||
|
||||
bool startsWith(const String16& prefix) const;
|
||||
bool startsWith(const char16_t* prefix) const;
|
||||
|
||||
status_t makeLower();
|
||||
|
||||
status_t replaceAll(char16_t replaceThis,
|
||||
char16_t withThis);
|
||||
|
||||
status_t remove(size_t len, size_t begin=0);
|
||||
|
||||
inline int compare(const String16& other) const;
|
||||
|
||||
inline bool operator<(const String16& other) const;
|
||||
inline bool operator<=(const String16& other) const;
|
||||
inline bool operator==(const String16& other) const;
|
||||
inline bool operator!=(const String16& other) const;
|
||||
inline bool operator>=(const String16& other) const;
|
||||
inline bool operator>(const String16& other) const;
|
||||
|
||||
inline bool operator<(const char16_t* other) const;
|
||||
inline bool operator<=(const char16_t* other) const;
|
||||
inline bool operator==(const char16_t* other) const;
|
||||
inline bool operator!=(const char16_t* other) const;
|
||||
inline bool operator>=(const char16_t* other) const;
|
||||
inline bool operator>(const char16_t* other) const;
|
||||
|
||||
inline operator const char16_t*() const;
|
||||
|
||||
private:
|
||||
const char16_t* mString;
|
||||
};
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const String16& val);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user servicable parts below.
|
||||
|
||||
inline int compare_type(const String16& lhs, const String16& rhs)
|
||||
{
|
||||
return lhs.compare(rhs);
|
||||
}
|
||||
|
||||
inline int strictly_order_type(const String16& lhs, const String16& rhs)
|
||||
{
|
||||
return compare_type(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
inline const char16_t* String16::string() const
|
||||
{
|
||||
return mString;
|
||||
}
|
||||
|
||||
inline size_t String16::size() const
|
||||
{
|
||||
return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
|
||||
}
|
||||
|
||||
inline const SharedBuffer* String16::sharedBuffer() const
|
||||
{
|
||||
return SharedBuffer::bufferFromData(mString);
|
||||
}
|
||||
|
||||
inline String16& String16::operator=(const String16& other)
|
||||
{
|
||||
setTo(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String16& String16::operator+=(const String16& other)
|
||||
{
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String16 String16::operator+(const String16& other) const
|
||||
{
|
||||
String16 tmp;
|
||||
tmp += other;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline int String16::compare(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size());
|
||||
}
|
||||
|
||||
inline bool String16::operator<(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size()) < 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator<=(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size()) <= 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator==(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size()) == 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator!=(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size()) != 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator>=(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size()) >= 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator>(const String16& other) const
|
||||
{
|
||||
return strzcmp16(mString, size(), other.mString, other.size()) > 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator<(const char16_t* other) const
|
||||
{
|
||||
return strcmp16(mString, other) < 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator<=(const char16_t* other) const
|
||||
{
|
||||
return strcmp16(mString, other) <= 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator==(const char16_t* other) const
|
||||
{
|
||||
return strcmp16(mString, other) == 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator!=(const char16_t* other) const
|
||||
{
|
||||
return strcmp16(mString, other) != 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator>=(const char16_t* other) const
|
||||
{
|
||||
return strcmp16(mString, other) >= 0;
|
||||
}
|
||||
|
||||
inline bool String16::operator>(const char16_t* other) const
|
||||
{
|
||||
return strcmp16(mString, other) > 0;
|
||||
}
|
||||
|
||||
inline String16::operator const char16_t*() const
|
||||
{
|
||||
return mString;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_STRING16_H
|
353
include/utils/String8.h
Normal file
353
include/utils/String8.h
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* 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_STRING8_H
|
||||
#define ANDROID_STRING8_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
|
||||
// Need this for the char16_t type; String8.h should not
|
||||
// be depedent on the String16 class.
|
||||
#include <utils/String16.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
class TextOutput;
|
||||
|
||||
//! This is a string holding UTF-8 characters.
|
||||
class String8
|
||||
{
|
||||
public:
|
||||
String8();
|
||||
String8(const String8& o);
|
||||
explicit String8(const char* o);
|
||||
explicit String8(const char* o, size_t numChars);
|
||||
|
||||
explicit String8(const String16& o);
|
||||
explicit String8(const char16_t* o);
|
||||
explicit String8(const char16_t* o, size_t numChars);
|
||||
|
||||
~String8();
|
||||
|
||||
inline const char* string() const;
|
||||
inline size_t size() const;
|
||||
inline size_t length() const;
|
||||
inline size_t bytes() const;
|
||||
|
||||
inline const SharedBuffer* sharedBuffer() const;
|
||||
|
||||
void setTo(const String8& other);
|
||||
status_t setTo(const char* other);
|
||||
status_t setTo(const char* other, size_t numChars);
|
||||
status_t setTo(const char16_t* other, size_t numChars);
|
||||
|
||||
status_t append(const String8& other);
|
||||
status_t append(const char* other);
|
||||
status_t append(const char* other, size_t numChars);
|
||||
|
||||
inline String8& operator=(const String8& other);
|
||||
inline String8& operator=(const char* other);
|
||||
|
||||
inline String8& operator+=(const String8& other);
|
||||
inline String8 operator+(const String8& other) const;
|
||||
|
||||
inline String8& operator+=(const char* other);
|
||||
inline String8 operator+(const char* other) const;
|
||||
|
||||
inline int compare(const String8& other) const;
|
||||
|
||||
inline bool operator<(const String8& other) const;
|
||||
inline bool operator<=(const String8& other) const;
|
||||
inline bool operator==(const String8& other) const;
|
||||
inline bool operator!=(const String8& other) const;
|
||||
inline bool operator>=(const String8& other) const;
|
||||
inline bool operator>(const String8& other) const;
|
||||
|
||||
inline bool operator<(const char* other) const;
|
||||
inline bool operator<=(const char* other) const;
|
||||
inline bool operator==(const char* other) const;
|
||||
inline bool operator!=(const char* other) const;
|
||||
inline bool operator>=(const char* other) const;
|
||||
inline bool operator>(const char* other) const;
|
||||
|
||||
inline operator const char*() const;
|
||||
|
||||
char* lockBuffer(size_t size);
|
||||
void unlockBuffer();
|
||||
status_t unlockBuffer(size_t size);
|
||||
|
||||
// return the index of the first byte of other in this at or after
|
||||
// start, or -1 if not found
|
||||
ssize_t find(const char* other, size_t start = 0) const;
|
||||
|
||||
void toLower();
|
||||
void toLower(size_t start, size_t numChars);
|
||||
void toUpper();
|
||||
void toUpper(size_t start, size_t numChars);
|
||||
|
||||
/*
|
||||
* These methods operate on the string as if it were a path name.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set the filename field to a specific value.
|
||||
*
|
||||
* Normalizes the filename, removing a trailing '/' if present.
|
||||
*/
|
||||
void setPathName(const char* name);
|
||||
void setPathName(const char* name, size_t numChars);
|
||||
|
||||
/*
|
||||
* Get just the filename component.
|
||||
*
|
||||
* "/tmp/foo/bar.c" --> "bar.c"
|
||||
*/
|
||||
String8 getPathLeaf(void) const;
|
||||
|
||||
/*
|
||||
* Remove the last (file name) component, leaving just the directory
|
||||
* name.
|
||||
*
|
||||
* "/tmp/foo/bar.c" --> "/tmp/foo"
|
||||
* "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
|
||||
* "bar.c" --> ""
|
||||
*/
|
||||
String8 getPathDir(void) const;
|
||||
|
||||
/*
|
||||
* Retrieve the front (root dir) component. Optionally also return the
|
||||
* remaining components.
|
||||
*
|
||||
* "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
|
||||
* "/tmp" --> "tmp" (remain = "")
|
||||
* "bar.c" --> "bar.c" (remain = "")
|
||||
*/
|
||||
String8 walkPath(String8* outRemains = NULL) const;
|
||||
|
||||
/*
|
||||
* Return the filename extension. This is the last '.' and up to
|
||||
* four characters that follow it. The '.' is included in case we
|
||||
* decide to expand our definition of what constitutes an extension.
|
||||
*
|
||||
* "/tmp/foo/bar.c" --> ".c"
|
||||
* "/tmp" --> ""
|
||||
* "/tmp/foo.bar/baz" --> ""
|
||||
* "foo.jpeg" --> ".jpeg"
|
||||
* "foo." --> ""
|
||||
*/
|
||||
String8 getPathExtension(void) const;
|
||||
|
||||
/*
|
||||
* Return the path without the extension. Rules for what constitutes
|
||||
* an extension are described in the comment for getPathExtension().
|
||||
*
|
||||
* "/tmp/foo/bar.c" --> "/tmp/foo/bar"
|
||||
*/
|
||||
String8 getBasePath(void) const;
|
||||
|
||||
/*
|
||||
* Add a component to the pathname. We guarantee that there is
|
||||
* exactly one path separator between the old path and the new.
|
||||
* If there is no existing name, we just copy the new name in.
|
||||
*
|
||||
* If leaf is a fully qualified path (i.e. starts with '/', it
|
||||
* replaces whatever was there before.
|
||||
*/
|
||||
String8& appendPath(const char* leaf);
|
||||
String8& appendPath(const String8& leaf) { return appendPath(leaf.string()); }
|
||||
|
||||
/*
|
||||
* Like appendPath(), but does not affect this string. Returns a new one instead.
|
||||
*/
|
||||
String8 appendPathCopy(const char* leaf) const
|
||||
{ String8 p(*this); p.appendPath(leaf); return p; }
|
||||
String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); }
|
||||
|
||||
/*
|
||||
* Converts all separators in this string to /, the default path separator.
|
||||
*
|
||||
* If the default OS separator is backslash, this converts all
|
||||
* backslashes to slashes, in-place. Otherwise it does nothing.
|
||||
* Returns self.
|
||||
*/
|
||||
String8& convertToResPath();
|
||||
|
||||
private:
|
||||
status_t real_append(const char* other, size_t numChars);
|
||||
char* find_extension(void) const;
|
||||
|
||||
const char* mString;
|
||||
};
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const String16& val);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user servicable parts below.
|
||||
|
||||
inline int compare_type(const String8& lhs, const String8& rhs)
|
||||
{
|
||||
return lhs.compare(rhs);
|
||||
}
|
||||
|
||||
inline int strictly_order_type(const String8& lhs, const String8& rhs)
|
||||
{
|
||||
return compare_type(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
inline const char* String8::string() const
|
||||
{
|
||||
return mString;
|
||||
}
|
||||
|
||||
inline size_t String8::length() const
|
||||
{
|
||||
return SharedBuffer::sizeFromData(mString)-1;
|
||||
}
|
||||
|
||||
inline size_t String8::size() const
|
||||
{
|
||||
return length();
|
||||
}
|
||||
|
||||
inline size_t String8::bytes() const
|
||||
{
|
||||
return SharedBuffer::sizeFromData(mString)-1;
|
||||
}
|
||||
|
||||
inline const SharedBuffer* String8::sharedBuffer() const
|
||||
{
|
||||
return SharedBuffer::bufferFromData(mString);
|
||||
}
|
||||
|
||||
inline String8& String8::operator=(const String8& other)
|
||||
{
|
||||
setTo(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String8& String8::operator=(const char* other)
|
||||
{
|
||||
setTo(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String8& String8::operator+=(const String8& other)
|
||||
{
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String8 String8::operator+(const String8& other) const
|
||||
{
|
||||
String8 tmp;
|
||||
tmp += other;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline String8& String8::operator+=(const char* other)
|
||||
{
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline String8 String8::operator+(const char* other) const
|
||||
{
|
||||
String8 tmp;
|
||||
tmp += other;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline int String8::compare(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString);
|
||||
}
|
||||
|
||||
inline bool String8::operator<(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString) < 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator<=(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString) <= 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator==(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString) == 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator!=(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString) != 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator>=(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString) >= 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator>(const String8& other) const
|
||||
{
|
||||
return strcmp(mString, other.mString) > 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator<(const char* other) const
|
||||
{
|
||||
return strcmp(mString, other) < 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator<=(const char* other) const
|
||||
{
|
||||
return strcmp(mString, other) <= 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator==(const char* other) const
|
||||
{
|
||||
return strcmp(mString, other) == 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator!=(const char* other) const
|
||||
{
|
||||
return strcmp(mString, other) != 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator>=(const char* other) const
|
||||
{
|
||||
return strcmp(mString, other) >= 0;
|
||||
}
|
||||
|
||||
inline bool String8::operator>(const char* other) const
|
||||
{
|
||||
return strcmp(mString, other) > 0;
|
||||
}
|
||||
|
||||
inline String8::operator const char*() const
|
||||
{
|
||||
return mString;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_STRING8_H
|
32
include/utils/SystemClock.h
Normal file
32
include/utils/SystemClock.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 ANDROID_UTILS_SYSTEMCLOCK_H
|
||||
#define ANDROID_UTILS_SYSTEMCLOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
int setCurrentTimeMillis(int64_t millis);
|
||||
int64_t uptimeMillis();
|
||||
int64_t elapsedRealtime();
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_UTILS_SYSTEMCLOCK_H
|
||||
|
190
include/utils/TextOutput.h
Normal file
190
include/utils/TextOutput.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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 ANDROID_TEXTOUTPUT_H
|
||||
#define ANDROID_TEXTOUTPUT_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace android {
|
||||
|
||||
class TextOutput
|
||||
{
|
||||
public:
|
||||
TextOutput() { }
|
||||
virtual ~TextOutput() { }
|
||||
|
||||
virtual status_t print(const char* txt, size_t len) = 0;
|
||||
virtual void moveIndent(int delta) = 0;
|
||||
|
||||
class Bundle {
|
||||
public:
|
||||
inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
|
||||
inline ~Bundle() { mTO.popBundle(); }
|
||||
private:
|
||||
TextOutput& mTO;
|
||||
};
|
||||
|
||||
virtual void pushBundle() = 0;
|
||||
virtual void popBundle() = 0;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Text output stream for printing to the log (via utils/Log.h).
|
||||
extern TextOutput& alog;
|
||||
|
||||
// Text output stream for printing to stdout.
|
||||
extern TextOutput& aout;
|
||||
|
||||
// Text output stream for printing to stderr.
|
||||
extern TextOutput& aerr;
|
||||
|
||||
typedef TextOutput& (*TextOutputManipFunc)(TextOutput&);
|
||||
|
||||
TextOutput& endl(TextOutput& to);
|
||||
TextOutput& indent(TextOutput& to);
|
||||
TextOutput& dedent(TextOutput& to);
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const char* str);
|
||||
TextOutput& operator<<(TextOutput& to, char); // writes raw character
|
||||
TextOutput& operator<<(TextOutput& to, bool);
|
||||
TextOutput& operator<<(TextOutput& to, int);
|
||||
TextOutput& operator<<(TextOutput& to, long);
|
||||
TextOutput& operator<<(TextOutput& to, unsigned int);
|
||||
TextOutput& operator<<(TextOutput& to, unsigned long);
|
||||
TextOutput& operator<<(TextOutput& to, long long);
|
||||
TextOutput& operator<<(TextOutput& to, unsigned long long);
|
||||
TextOutput& operator<<(TextOutput& to, float);
|
||||
TextOutput& operator<<(TextOutput& to, double);
|
||||
TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
|
||||
TextOutput& operator<<(TextOutput& to, const void*);
|
||||
|
||||
class TypeCode
|
||||
{
|
||||
public:
|
||||
inline TypeCode(uint32_t code);
|
||||
inline ~TypeCode();
|
||||
|
||||
inline uint32_t typeCode() const;
|
||||
|
||||
private:
|
||||
uint32_t mCode;
|
||||
};
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const TypeCode& val);
|
||||
|
||||
class HexDump
|
||||
{
|
||||
public:
|
||||
HexDump(const void *buf, size_t size, size_t bytesPerLine=16);
|
||||
inline ~HexDump();
|
||||
|
||||
inline HexDump& setBytesPerLine(size_t bytesPerLine);
|
||||
inline HexDump& setSingleLineCutoff(int32_t bytes);
|
||||
inline HexDump& setAlignment(size_t alignment);
|
||||
inline HexDump& setCArrayStyle(bool enabled);
|
||||
|
||||
inline const void* buffer() const;
|
||||
inline size_t size() const;
|
||||
inline size_t bytesPerLine() const;
|
||||
inline int32_t singleLineCutoff() const;
|
||||
inline size_t alignment() const;
|
||||
inline bool carrayStyle() const;
|
||||
|
||||
private:
|
||||
const void* mBuffer;
|
||||
size_t mSize;
|
||||
size_t mBytesPerLine;
|
||||
int32_t mSingleLineCutoff;
|
||||
size_t mAlignment;
|
||||
bool mCArrayStyle;
|
||||
};
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const HexDump& val);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user servicable parts below.
|
||||
|
||||
inline TextOutput& endl(TextOutput& to)
|
||||
{
|
||||
to.print("\n", 1);
|
||||
return to;
|
||||
}
|
||||
|
||||
inline TextOutput& indent(TextOutput& to)
|
||||
{
|
||||
to.moveIndent(1);
|
||||
return to;
|
||||
}
|
||||
|
||||
inline TextOutput& dedent(TextOutput& to)
|
||||
{
|
||||
to.moveIndent(-1);
|
||||
return to;
|
||||
}
|
||||
|
||||
inline TextOutput& operator<<(TextOutput& to, const char* str)
|
||||
{
|
||||
to.print(str, strlen(str));
|
||||
return to;
|
||||
}
|
||||
|
||||
inline TextOutput& operator<<(TextOutput& to, char c)
|
||||
{
|
||||
to.print(&c, 1);
|
||||
return to;
|
||||
}
|
||||
|
||||
inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func)
|
||||
{
|
||||
return (*func)(to);
|
||||
}
|
||||
|
||||
inline TypeCode::TypeCode(uint32_t code) : mCode(code) { }
|
||||
inline TypeCode::~TypeCode() { }
|
||||
inline uint32_t TypeCode::typeCode() const { return mCode; }
|
||||
|
||||
inline HexDump::~HexDump() { }
|
||||
|
||||
inline HexDump& HexDump::setBytesPerLine(size_t bytesPerLine) {
|
||||
mBytesPerLine = bytesPerLine; return *this;
|
||||
}
|
||||
inline HexDump& HexDump::setSingleLineCutoff(int32_t bytes) {
|
||||
mSingleLineCutoff = bytes; return *this;
|
||||
}
|
||||
inline HexDump& HexDump::setAlignment(size_t alignment) {
|
||||
mAlignment = alignment; return *this;
|
||||
}
|
||||
inline HexDump& HexDump::setCArrayStyle(bool enabled) {
|
||||
mCArrayStyle = enabled; return *this;
|
||||
}
|
||||
|
||||
inline const void* HexDump::buffer() const { return mBuffer; }
|
||||
inline size_t HexDump::size() const { return mSize; }
|
||||
inline size_t HexDump::bytesPerLine() const { return mBytesPerLine; }
|
||||
inline int32_t HexDump::singleLineCutoff() const { return mSingleLineCutoff; }
|
||||
inline size_t HexDump::alignment() const { return mAlignment; }
|
||||
inline bool HexDump::carrayStyle() const { return mCArrayStyle; }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_TEXTOUTPUT_H
|
89
include/utils/TimeUtils.h
Normal file
89
include/utils/TimeUtils.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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_TIME_H
|
||||
#define ANDROID_TIME_H
|
||||
|
||||
#include <time.h>
|
||||
#include <cutils/tztime.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/String16.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* This class is the core implementation of the android.util.Time java
|
||||
* class. It doesn't implement some of the methods that are implemented
|
||||
* in Java. They could be done here, but it's not expected that this class
|
||||
* will be used. If that assumption is incorrect, feel free to update this
|
||||
* file. The reason to do it here is to not mix the implementation of this
|
||||
* class and the jni glue code.
|
||||
*/
|
||||
class Time
|
||||
{
|
||||
public:
|
||||
struct tm t;
|
||||
|
||||
// this object doesn't own this string
|
||||
const char *timezone;
|
||||
|
||||
enum {
|
||||
SEC = 1,
|
||||
MIN = 2,
|
||||
HOUR = 3,
|
||||
MDAY = 4,
|
||||
MON = 5,
|
||||
YEAR = 6,
|
||||
WDAY = 7,
|
||||
YDAY = 8
|
||||
};
|
||||
|
||||
static int compare(Time& a, Time& b);
|
||||
|
||||
Time();
|
||||
|
||||
void switchTimezone(const char *timezone);
|
||||
String8 format(const char *format, const struct strftime_locale *locale) const;
|
||||
void format2445(short* buf, bool hasTime) const;
|
||||
String8 toString() const;
|
||||
void setToNow();
|
||||
int64_t toMillis(bool ignoreDst);
|
||||
void set(int64_t millis);
|
||||
|
||||
inline void set(int sec, int min, int hour, int mday, int mon, int year,
|
||||
int isdst)
|
||||
{
|
||||
this->t.tm_sec = sec;
|
||||
this->t.tm_min = min;
|
||||
this->t.tm_hour = hour;
|
||||
this->t.tm_mday = mday;
|
||||
this->t.tm_mon = mon;
|
||||
this->t.tm_year = year;
|
||||
this->t.tm_isdst = isdst;
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
this->t.tm_gmtoff = 0;
|
||||
#endif
|
||||
this->t.tm_wday = 0;
|
||||
this->t.tm_yday = 0;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_TIME_H
|
72
include/utils/TimerProbe.h
Normal file
72
include/utils/TimerProbe.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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_TIMER_PROBE_H
|
||||
#define ANDROID_TIMER_PROBE_H
|
||||
|
||||
#if 0 && defined(HAVE_POSIX_CLOCKS)
|
||||
#define ENABLE_TIMER_PROBE 1
|
||||
#else
|
||||
#define ENABLE_TIMER_PROBE 0
|
||||
#endif
|
||||
|
||||
#if ENABLE_TIMER_PROBE
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#define TIMER_PROBE(tag) \
|
||||
static int _timer_slot_; \
|
||||
android::TimerProbe probe(tag, &_timer_slot_)
|
||||
#define TIMER_PROBE_END() probe.end()
|
||||
#else
|
||||
#define TIMER_PROBE(tag)
|
||||
#define TIMER_PROBE_END()
|
||||
#endif
|
||||
|
||||
#if ENABLE_TIMER_PROBE
|
||||
namespace android {
|
||||
|
||||
class TimerProbe {
|
||||
public:
|
||||
TimerProbe(const char tag[], int* slot);
|
||||
void end();
|
||||
~TimerProbe();
|
||||
private:
|
||||
struct Bucket {
|
||||
int mStart, mReal, mProcess, mThread, mCount;
|
||||
const char* mTag;
|
||||
int* mSlotPtr;
|
||||
int mIndent;
|
||||
};
|
||||
static Vector<Bucket> gBuckets;
|
||||
static TimerProbe* gExecuteChain;
|
||||
static int gIndent;
|
||||
static timespec gRealBase;
|
||||
TimerProbe* mNext;
|
||||
static uint32_t ElapsedTime(const timespec& start, const timespec& end);
|
||||
void print(const timespec& r, const timespec& p, const timespec& t) const;
|
||||
timespec mRealStart, mPStart, mTStart;
|
||||
const char* mTag;
|
||||
int mIndent;
|
||||
int mBucket;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
||||
#endif
|
137
include/utils/Timers.h
Normal file
137
include/utils/Timers.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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Timer functions.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_TIMERS_H
|
||||
#define _LIBS_UTILS_TIMERS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// C API
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int64_t nsecs_t; // nano-seconds
|
||||
|
||||
static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
|
||||
{
|
||||
return secs*1000000000;
|
||||
}
|
||||
|
||||
static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
|
||||
{
|
||||
return secs*1000000;
|
||||
}
|
||||
|
||||
static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
|
||||
{
|
||||
return secs*1000;
|
||||
}
|
||||
|
||||
static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
|
||||
{
|
||||
return secs/1000000000;
|
||||
}
|
||||
|
||||
static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
|
||||
{
|
||||
return secs/1000000;
|
||||
}
|
||||
|
||||
static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
|
||||
{
|
||||
return secs/1000;
|
||||
}
|
||||
|
||||
static inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);}
|
||||
static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
|
||||
static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
|
||||
static inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);}
|
||||
static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
|
||||
static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
|
||||
|
||||
static inline nsecs_t seconds(nsecs_t v) { return s2ns(v); }
|
||||
static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
|
||||
static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
|
||||
|
||||
enum {
|
||||
SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
|
||||
SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
|
||||
SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock
|
||||
SYSTEM_TIME_THREAD = 3 // high-resolution per-thread clock
|
||||
};
|
||||
|
||||
// return the system-time according to the specified clock
|
||||
#ifdef __cplusplus
|
||||
nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
|
||||
#else
|
||||
nsecs_t systemTime(int clock);
|
||||
#endif // def __cplusplus
|
||||
|
||||
// return the system-time according to the specified clock
|
||||
int sleepForInterval(long interval, struct timeval* pNextTick);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// C++ API
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace android {
|
||||
/*
|
||||
* Time the duration of something.
|
||||
*
|
||||
* Includes some timeval manipulation functions.
|
||||
*/
|
||||
class DurationTimer {
|
||||
public:
|
||||
DurationTimer(void) {}
|
||||
~DurationTimer(void) {}
|
||||
|
||||
// Start the timer.
|
||||
void start(void);
|
||||
// Stop the timer.
|
||||
void stop(void);
|
||||
// Get the duration in microseconds.
|
||||
long long durationUsecs(void) const;
|
||||
|
||||
// Subtract two timevals. Returns the difference (ptv1-ptv2) in
|
||||
// microseconds.
|
||||
static long long subtractTimevals(const struct timeval* ptv1,
|
||||
const struct timeval* ptv2);
|
||||
|
||||
// Add the specified amount of time to the timeval.
|
||||
static void addToTimeval(struct timeval* ptv, long usec);
|
||||
|
||||
private:
|
||||
struct timeval mStartWhen;
|
||||
struct timeval mStopWhen;
|
||||
};
|
||||
|
||||
}; // android
|
||||
#endif // def __cplusplus
|
||||
|
||||
#endif // _LIBS_UTILS_TIMERS_H
|
254
include/utils/TypeHelpers.h
Normal file
254
include/utils/TypeHelpers.h
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* 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_TYPE_HELPERS_H
|
||||
#define ANDROID_TYPE_HELPERS_H
|
||||
|
||||
#include <new>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Types traits
|
||||
*/
|
||||
|
||||
template <typename T> struct trait_trivial_ctor { enum { value = false }; };
|
||||
template <typename T> struct trait_trivial_dtor { enum { value = false }; };
|
||||
template <typename T> struct trait_trivial_copy { enum { value = false }; };
|
||||
template <typename T> struct trait_trivial_assign{ enum { value = false }; };
|
||||
|
||||
template <typename T> struct trait_pointer { enum { value = false }; };
|
||||
template <typename T> struct trait_pointer<T*> { enum { value = true }; };
|
||||
|
||||
#define ANDROID_BASIC_TYPES_TRAITS( T ) \
|
||||
template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
|
||||
template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
|
||||
template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
|
||||
template<> struct trait_trivial_assign< T >{ enum { value = true }; };
|
||||
|
||||
#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
|
||||
template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
|
||||
template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
|
||||
template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
|
||||
template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
|
||||
|
||||
template <typename TYPE>
|
||||
struct traits {
|
||||
enum {
|
||||
is_pointer = trait_pointer<TYPE>::value,
|
||||
has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
|
||||
has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
|
||||
has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
|
||||
has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct aggregate_traits {
|
||||
enum {
|
||||
is_pointer = false,
|
||||
has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
|
||||
has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
|
||||
has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
|
||||
has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
|
||||
};
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* basic types traits
|
||||
*/
|
||||
|
||||
ANDROID_BASIC_TYPES_TRAITS( void );
|
||||
ANDROID_BASIC_TYPES_TRAITS( bool );
|
||||
ANDROID_BASIC_TYPES_TRAITS( char );
|
||||
ANDROID_BASIC_TYPES_TRAITS( unsigned char );
|
||||
ANDROID_BASIC_TYPES_TRAITS( short );
|
||||
ANDROID_BASIC_TYPES_TRAITS( unsigned short );
|
||||
ANDROID_BASIC_TYPES_TRAITS( int );
|
||||
ANDROID_BASIC_TYPES_TRAITS( unsigned int );
|
||||
ANDROID_BASIC_TYPES_TRAITS( long );
|
||||
ANDROID_BASIC_TYPES_TRAITS( unsigned long );
|
||||
ANDROID_BASIC_TYPES_TRAITS( long long );
|
||||
ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
|
||||
ANDROID_BASIC_TYPES_TRAITS( float );
|
||||
ANDROID_BASIC_TYPES_TRAITS( double );
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
* compare and order types
|
||||
*/
|
||||
|
||||
template<typename TYPE> inline
|
||||
int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
|
||||
return (lhs < rhs) ? 1 : 0;
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
int compare_type(const TYPE& lhs, const TYPE& rhs) {
|
||||
return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
|
||||
}
|
||||
|
||||
/*
|
||||
* create, destroy, copy and assign types...
|
||||
*/
|
||||
|
||||
template<typename TYPE> inline
|
||||
void construct_type(TYPE* p, size_t n) {
|
||||
if (!traits<TYPE>::has_trivial_ctor) {
|
||||
while (n--) {
|
||||
new(p++) TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
void destroy_type(TYPE* p, size_t n) {
|
||||
if (!traits<TYPE>::has_trivial_dtor) {
|
||||
while (n--) {
|
||||
p->~TYPE();
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
void copy_type(TYPE* d, const TYPE* s, size_t n) {
|
||||
if (!traits<TYPE>::has_trivial_copy) {
|
||||
while (n--) {
|
||||
new(d) TYPE(*s);
|
||||
d++, s++;
|
||||
}
|
||||
} else {
|
||||
memcpy(d,s,n*sizeof(TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
void assign_type(TYPE* d, const TYPE* s, size_t n) {
|
||||
if (!traits<TYPE>::has_trivial_assign) {
|
||||
while (n--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
} else {
|
||||
memcpy(d,s,n*sizeof(TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
void splat_type(TYPE* where, const TYPE* what, size_t n) {
|
||||
if (!traits<TYPE>::has_trivial_copy) {
|
||||
while (n--) {
|
||||
new(where) TYPE(*what);
|
||||
where++;
|
||||
}
|
||||
} else {
|
||||
while (n--) {
|
||||
*where++ = *what;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
|
||||
if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
|
||||
d += n;
|
||||
s += n;
|
||||
while (n--) {
|
||||
--d, --s;
|
||||
if (!traits<TYPE>::has_trivial_copy) {
|
||||
new(d) TYPE(*s);
|
||||
} else {
|
||||
*d = *s;
|
||||
}
|
||||
if (!traits<TYPE>::has_trivial_dtor) {
|
||||
s->~TYPE();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memmove(d,s,n*sizeof(TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TYPE> inline
|
||||
void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
|
||||
if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
|
||||
while (n--) {
|
||||
if (!traits<TYPE>::has_trivial_copy) {
|
||||
new(d) TYPE(*s);
|
||||
} else {
|
||||
*d = *s;
|
||||
}
|
||||
if (!traits<TYPE>::has_trivial_dtor) {
|
||||
s->~TYPE();
|
||||
}
|
||||
d++, s++;
|
||||
}
|
||||
} else {
|
||||
memmove(d,s,n*sizeof(TYPE));
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* a key/value pair
|
||||
*/
|
||||
|
||||
template <typename KEY, typename VALUE>
|
||||
struct key_value_pair_t {
|
||||
KEY key;
|
||||
VALUE value;
|
||||
key_value_pair_t() { }
|
||||
key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
|
||||
key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { }
|
||||
key_value_pair_t(const KEY& k) : key(k) { }
|
||||
inline bool operator < (const key_value_pair_t& o) const {
|
||||
return strictly_order_type(key, o.key);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
template <typename K, typename V>
|
||||
struct trait_trivial_ctor< key_value_pair_t<K, V> >
|
||||
{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
|
||||
template<>
|
||||
template <typename K, typename V>
|
||||
struct trait_trivial_dtor< key_value_pair_t<K, V> >
|
||||
{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
|
||||
template<>
|
||||
template <typename K, typename V>
|
||||
struct trait_trivial_copy< key_value_pair_t<K, V> >
|
||||
{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
|
||||
template<>
|
||||
template <typename K, typename V>
|
||||
struct trait_trivial_assign< key_value_pair_t<K, V> >
|
||||
{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_TYPE_HELPERS_H
|
359
include/utils/Vector.h
Normal file
359
include/utils/Vector.h
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* 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_VECTOR_H
|
||||
#define ANDROID_VECTOR_H
|
||||
|
||||
#include <new>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/VectorImpl.h>
|
||||
#include <utils/TypeHelpers.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
/*!
|
||||
* The main templated vector class ensuring type safety
|
||||
* while making use of VectorImpl.
|
||||
* This is the class users want to use.
|
||||
*/
|
||||
|
||||
template <class TYPE>
|
||||
class Vector : private VectorImpl
|
||||
{
|
||||
public:
|
||||
typedef TYPE value_type;
|
||||
|
||||
/*!
|
||||
* Constructors and destructors
|
||||
*/
|
||||
|
||||
Vector();
|
||||
Vector(const Vector<TYPE>& rhs);
|
||||
virtual ~Vector();
|
||||
|
||||
/*! copy operator */
|
||||
const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const;
|
||||
Vector<TYPE>& operator = (const Vector<TYPE>& rhs);
|
||||
|
||||
/*
|
||||
* empty the vector
|
||||
*/
|
||||
|
||||
inline void clear() { VectorImpl::clear(); }
|
||||
|
||||
/*!
|
||||
* vector stats
|
||||
*/
|
||||
|
||||
//! returns number of items in the vector
|
||||
inline size_t size() const { return VectorImpl::size(); }
|
||||
//! returns wether or not the vector is empty
|
||||
inline bool isEmpty() const { return VectorImpl::isEmpty(); }
|
||||
//! returns how many items can be stored without reallocating the backing store
|
||||
inline size_t capacity() const { return VectorImpl::capacity(); }
|
||||
//! setst the capacity. capacity can never be reduced less than size()
|
||||
inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
|
||||
|
||||
/*!
|
||||
* C-style array access
|
||||
*/
|
||||
|
||||
//! read-only C-style access
|
||||
inline const TYPE* array() const;
|
||||
//! read-write C-style access
|
||||
TYPE* editArray();
|
||||
|
||||
/*!
|
||||
* accessors
|
||||
*/
|
||||
|
||||
//! read-only access to an item at a given index
|
||||
inline const TYPE& operator [] (size_t index) const;
|
||||
//! alternate name for operator []
|
||||
inline const TYPE& itemAt(size_t index) const;
|
||||
//! stack-usage of the vector. returns the top of the stack (last element)
|
||||
const TYPE& top() const;
|
||||
//! same as operator [], but allows to access the vector backward (from the end) with a negative index
|
||||
const TYPE& mirrorItemAt(ssize_t index) const;
|
||||
|
||||
/*!
|
||||
* modifing the array
|
||||
*/
|
||||
|
||||
//! copy-on write support, grants write access to an item
|
||||
TYPE& editItemAt(size_t index);
|
||||
//! grants right acces to the top of the stack (last element)
|
||||
TYPE& editTop();
|
||||
|
||||
/*!
|
||||
* append/insert another vector
|
||||
*/
|
||||
|
||||
//! insert another vector at a given index
|
||||
ssize_t insertVectorAt(const Vector<TYPE>& vector, size_t index);
|
||||
|
||||
//! append another vector at the end of this one
|
||||
ssize_t appendVector(const Vector<TYPE>& vector);
|
||||
|
||||
|
||||
/*!
|
||||
* add/insert/replace items
|
||||
*/
|
||||
|
||||
//! insert one or several items initialized with their default constructor
|
||||
inline ssize_t insertAt(size_t index, size_t numItems = 1);
|
||||
//! insert on onr several items initialized from a prototype item
|
||||
ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
|
||||
//! pop the top of the stack (removes the last element). No-op if the stack's empty
|
||||
inline void pop();
|
||||
//! pushes an item initialized with its default constructor
|
||||
inline void push();
|
||||
//! pushes an item on the top of the stack
|
||||
void push(const TYPE& item);
|
||||
//! same as push() but returns the index the item was added at (or an error)
|
||||
inline ssize_t add();
|
||||
//! same as push() but returns the index the item was added at (or an error)
|
||||
ssize_t add(const TYPE& item);
|
||||
//! replace an item with a new one initialized with its default constructor
|
||||
inline ssize_t replaceAt(size_t index);
|
||||
//! replace an item with a new one
|
||||
ssize_t replaceAt(const TYPE& item, size_t index);
|
||||
|
||||
/*!
|
||||
* remove items
|
||||
*/
|
||||
|
||||
//! remove several items
|
||||
inline ssize_t removeItemsAt(size_t index, size_t count = 1);
|
||||
//! remove one item
|
||||
inline ssize_t removeAt(size_t index) { return removeItemsAt(index); }
|
||||
|
||||
/*!
|
||||
* sort (stable) the array
|
||||
*/
|
||||
|
||||
typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
|
||||
typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
|
||||
|
||||
inline status_t sort(compar_t cmp);
|
||||
inline status_t sort(compar_r_t cmp, void* state);
|
||||
|
||||
protected:
|
||||
virtual void do_construct(void* storage, size_t num) const;
|
||||
virtual void do_destroy(void* storage, size_t num) const;
|
||||
virtual void do_copy(void* dest, const void* from, size_t num) const;
|
||||
virtual void do_splat(void* dest, const void* item, size_t num) const;
|
||||
virtual void do_move_forward(void* dest, const void* from, size_t num) const;
|
||||
virtual void do_move_backward(void* dest, const void* from, size_t num) const;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user serviceable parts from here...
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<class TYPE> inline
|
||||
Vector<TYPE>::Vector()
|
||||
: VectorImpl(sizeof(TYPE),
|
||||
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|
||||
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
|
||||
|(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
|
||||
|(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
|
||||
: VectorImpl(rhs) {
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
Vector<TYPE>::~Vector() {
|
||||
finish_vector();
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
|
||||
VectorImpl::operator = (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
|
||||
VectorImpl::operator = (rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE* Vector<TYPE>::array() const {
|
||||
return static_cast<const TYPE *>(arrayImpl());
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
TYPE* Vector<TYPE>::editArray() {
|
||||
return static_cast<TYPE *>(editArrayImpl());
|
||||
}
|
||||
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& Vector<TYPE>::operator[](size_t index) const {
|
||||
LOG_FATAL_IF( index>=size(),
|
||||
"itemAt: index %d is past size %d", (int)index, (int)size() );
|
||||
return *(array() + index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& Vector<TYPE>::itemAt(size_t index) const {
|
||||
return operator[](index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const {
|
||||
LOG_FATAL_IF( (index>0 ? index : -index)>=size(),
|
||||
"mirrorItemAt: index %d is past size %d",
|
||||
(int)index, (int)size() );
|
||||
return *(array() + ((index<0) ? (size()-index) : index));
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
const TYPE& Vector<TYPE>::top() const {
|
||||
return *(array() + size() - 1);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
TYPE& Vector<TYPE>::editItemAt(size_t index) {
|
||||
return *( static_cast<TYPE *>(editItemLocation(index)) );
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
TYPE& Vector<TYPE>::editTop() {
|
||||
return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
|
||||
return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
|
||||
return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
|
||||
return VectorImpl::insertAt(&item, index, numItems);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
void Vector<TYPE>::push(const TYPE& item) {
|
||||
return VectorImpl::push(&item);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::add(const TYPE& item) {
|
||||
return VectorImpl::add(&item);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
|
||||
return VectorImpl::replaceAt(&item, index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
|
||||
return VectorImpl::insertAt(index, numItems);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
void Vector<TYPE>::pop() {
|
||||
VectorImpl::pop();
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
void Vector<TYPE>::push() {
|
||||
VectorImpl::push();
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::add() {
|
||||
return VectorImpl::add();
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::replaceAt(size_t index) {
|
||||
return VectorImpl::replaceAt(index);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
|
||||
return VectorImpl::removeItemsAt(index, count);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
|
||||
return VectorImpl::sort((VectorImpl::compar_t)cmp);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
|
||||
return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<class TYPE>
|
||||
void Vector<TYPE>::do_construct(void* storage, size_t num) const {
|
||||
construct_type( reinterpret_cast<TYPE*>(storage), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
|
||||
destroy_type( reinterpret_cast<TYPE*>(storage), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
|
||||
copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
|
||||
splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
|
||||
move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
|
||||
move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_VECTOR_H
|
199
include/utils/VectorImpl.h
Normal file
199
include/utils/VectorImpl.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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_VECTOR_IMPL_H
|
||||
#define ANDROID_VECTOR_IMPL_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <utils/Errors.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// No user serviceable parts in here...
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
/*!
|
||||
* Implementation of the guts of the vector<> class
|
||||
* this ensures backward binary compatibility and
|
||||
* reduces code size.
|
||||
* For performance reasons, we expose mStorage and mCount
|
||||
* so these fields are set in stone.
|
||||
*
|
||||
*/
|
||||
|
||||
class VectorImpl
|
||||
{
|
||||
public:
|
||||
enum { // flags passed to the ctor
|
||||
HAS_TRIVIAL_CTOR = 0x00000001,
|
||||
HAS_TRIVIAL_DTOR = 0x00000002,
|
||||
HAS_TRIVIAL_COPY = 0x00000004,
|
||||
HAS_TRIVIAL_ASSIGN = 0x00000008
|
||||
};
|
||||
|
||||
VectorImpl(size_t itemSize, uint32_t flags);
|
||||
VectorImpl(const VectorImpl& rhs);
|
||||
virtual ~VectorImpl();
|
||||
|
||||
/*! must be called from subclasses destructor */
|
||||
void finish_vector();
|
||||
|
||||
VectorImpl& operator = (const VectorImpl& rhs);
|
||||
|
||||
/*! C-style array access */
|
||||
inline const void* arrayImpl() const { return mStorage; }
|
||||
void* editArrayImpl();
|
||||
|
||||
/*! vector stats */
|
||||
inline size_t size() const { return mCount; }
|
||||
inline bool isEmpty() const { return mCount == 0; }
|
||||
size_t capacity() const;
|
||||
ssize_t setCapacity(size_t size);
|
||||
|
||||
/*! append/insert another vector */
|
||||
ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
|
||||
ssize_t appendVector(const VectorImpl& vector);
|
||||
|
||||
/*! add/insert/replace items */
|
||||
ssize_t insertAt(size_t where, size_t numItems = 1);
|
||||
ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
|
||||
void pop();
|
||||
void push();
|
||||
void push(const void* item);
|
||||
ssize_t add();
|
||||
ssize_t add(const void* item);
|
||||
ssize_t replaceAt(size_t index);
|
||||
ssize_t replaceAt(const void* item, size_t index);
|
||||
|
||||
/*! remove items */
|
||||
ssize_t removeItemsAt(size_t index, size_t count = 1);
|
||||
void clear();
|
||||
|
||||
const void* itemLocation(size_t index) const;
|
||||
void* editItemLocation(size_t index);
|
||||
|
||||
typedef int (*compar_t)(const void* lhs, const void* rhs);
|
||||
typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state);
|
||||
status_t sort(compar_t cmp);
|
||||
status_t sort(compar_r_t cmp, void* state);
|
||||
|
||||
protected:
|
||||
size_t itemSize() const;
|
||||
void release_storage();
|
||||
|
||||
virtual void do_construct(void* storage, size_t num) const = 0;
|
||||
virtual void do_destroy(void* storage, size_t num) const = 0;
|
||||
virtual void do_copy(void* dest, const void* from, size_t num) const = 0;
|
||||
virtual void do_splat(void* dest, const void* item, size_t num) const = 0;
|
||||
virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0;
|
||||
virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0;
|
||||
|
||||
// take care of FBC...
|
||||
virtual void reservedVectorImpl1();
|
||||
virtual void reservedVectorImpl2();
|
||||
virtual void reservedVectorImpl3();
|
||||
virtual void reservedVectorImpl4();
|
||||
virtual void reservedVectorImpl5();
|
||||
virtual void reservedVectorImpl6();
|
||||
virtual void reservedVectorImpl7();
|
||||
virtual void reservedVectorImpl8();
|
||||
|
||||
private:
|
||||
void* _grow(size_t where, size_t amount);
|
||||
void _shrink(size_t where, size_t amount);
|
||||
|
||||
inline void _do_construct(void* storage, size_t num) const;
|
||||
inline void _do_destroy(void* storage, size_t num) const;
|
||||
inline void _do_copy(void* dest, const void* from, size_t num) const;
|
||||
inline void _do_splat(void* dest, const void* item, size_t num) const;
|
||||
inline void _do_move_forward(void* dest, const void* from, size_t num) const;
|
||||
inline void _do_move_backward(void* dest, const void* from, size_t num) const;
|
||||
|
||||
// These 2 fields are exposed in the inlines below,
|
||||
// so they're set in stone.
|
||||
void * mStorage; // base address of the vector
|
||||
size_t mCount; // number of items
|
||||
|
||||
const uint32_t mFlags;
|
||||
const size_t mItemSize;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SortedVectorImpl : public VectorImpl
|
||||
{
|
||||
public:
|
||||
SortedVectorImpl(size_t itemSize, uint32_t flags);
|
||||
SortedVectorImpl(const VectorImpl& rhs);
|
||||
virtual ~SortedVectorImpl();
|
||||
|
||||
SortedVectorImpl& operator = (const SortedVectorImpl& rhs);
|
||||
|
||||
//! finds the index of an item
|
||||
ssize_t indexOf(const void* item) const;
|
||||
|
||||
//! finds where this item should be inserted
|
||||
size_t orderOf(const void* item) const;
|
||||
|
||||
//! add an item in the right place (or replaces it if there is one)
|
||||
ssize_t add(const void* item);
|
||||
|
||||
//! merges a vector into this one
|
||||
ssize_t merge(const VectorImpl& vector);
|
||||
ssize_t merge(const SortedVectorImpl& vector);
|
||||
|
||||
//! removes an item
|
||||
ssize_t remove(const void* item);
|
||||
|
||||
protected:
|
||||
virtual int do_compare(const void* lhs, const void* rhs) const = 0;
|
||||
|
||||
// take care of FBC...
|
||||
virtual void reservedSortedVectorImpl1();
|
||||
virtual void reservedSortedVectorImpl2();
|
||||
virtual void reservedSortedVectorImpl3();
|
||||
virtual void reservedSortedVectorImpl4();
|
||||
virtual void reservedSortedVectorImpl5();
|
||||
virtual void reservedSortedVectorImpl6();
|
||||
virtual void reservedSortedVectorImpl7();
|
||||
virtual void reservedSortedVectorImpl8();
|
||||
|
||||
private:
|
||||
ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
|
||||
|
||||
// these are made private, because they can't be used on a SortedVector
|
||||
// (they don't have an implementation either)
|
||||
ssize_t add();
|
||||
void pop();
|
||||
void push();
|
||||
void push(const void* item);
|
||||
ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
|
||||
ssize_t appendVector(const VectorImpl& vector);
|
||||
ssize_t insertAt(size_t where, size_t numItems = 1);
|
||||
ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
|
||||
ssize_t replaceAt(size_t index);
|
||||
ssize_t replaceAt(const void* item, size_t index);
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#endif // ANDROID_VECTOR_IMPL_H
|
345
include/utils/ZipEntry.h
Normal file
345
include/utils/ZipEntry.h
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Zip archive entries.
|
||||
//
|
||||
// The ZipEntry class is tightly meshed with the ZipFile class.
|
||||
//
|
||||
#ifndef __LIBS_ZIPENTRY_H
|
||||
#define __LIBS_ZIPENTRY_H
|
||||
|
||||
#include "Errors.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class ZipFile;
|
||||
|
||||
/*
|
||||
* ZipEntry objects represent a single entry in a Zip archive.
|
||||
*
|
||||
* You can use one of these to get or set information about an entry, but
|
||||
* there are no functions here for accessing the data itself. (We could
|
||||
* tuck a pointer to the ZipFile in here for convenience, but that raises
|
||||
* the likelihood of using ZipEntry objects after discarding the ZipFile.)
|
||||
*
|
||||
* File information is stored in two places: next to the file data (the Local
|
||||
* File Header, and possibly a Data Descriptor), and at the end of the file
|
||||
* (the Central Directory Entry). The two must be kept in sync.
|
||||
*/
|
||||
class ZipEntry {
|
||||
public:
|
||||
friend class ZipFile;
|
||||
|
||||
ZipEntry(void)
|
||||
: mDeleted(false), mMarked(false)
|
||||
{}
|
||||
~ZipEntry(void) {}
|
||||
|
||||
/*
|
||||
* Returns "true" if the data is compressed.
|
||||
*/
|
||||
bool isCompressed(void) const {
|
||||
return mCDE.mCompressionMethod != kCompressStored;
|
||||
}
|
||||
int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
|
||||
|
||||
/*
|
||||
* Return the uncompressed length.
|
||||
*/
|
||||
off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
|
||||
|
||||
/*
|
||||
* Return the compressed length. For uncompressed data, this returns
|
||||
* the same thing as getUncompresesdLen().
|
||||
*/
|
||||
off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
|
||||
|
||||
/*
|
||||
* Return the absolute file offset of the start of the compressed or
|
||||
* uncompressed data.
|
||||
*/
|
||||
off_t getFileOffset(void) const {
|
||||
return mCDE.mLocalHeaderRelOffset +
|
||||
LocalFileHeader::kLFHLen +
|
||||
mLFH.mFileNameLength +
|
||||
mLFH.mExtraFieldLength;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the data CRC.
|
||||
*/
|
||||
unsigned long getCRC32(void) const { return mCDE.mCRC32; }
|
||||
|
||||
/*
|
||||
* Return file modification time in UNIX seconds-since-epoch.
|
||||
*/
|
||||
time_t getModWhen(void) const;
|
||||
|
||||
/*
|
||||
* Return the archived file name.
|
||||
*/
|
||||
const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
|
||||
|
||||
/*
|
||||
* Application-defined "mark". Can be useful when synchronizing the
|
||||
* contents of an archive with contents on disk.
|
||||
*/
|
||||
bool getMarked(void) const { return mMarked; }
|
||||
void setMarked(bool val) { mMarked = val; }
|
||||
|
||||
/*
|
||||
* Some basic functions for raw data manipulation. "LE" means
|
||||
* Little Endian.
|
||||
*/
|
||||
static inline unsigned short getShortLE(const unsigned char* buf) {
|
||||
return buf[0] | (buf[1] << 8);
|
||||
}
|
||||
static inline unsigned long getLongLE(const unsigned char* buf) {
|
||||
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
}
|
||||
static inline void putShortLE(unsigned char* buf, short val) {
|
||||
buf[0] = (unsigned char) val;
|
||||
buf[1] = (unsigned char) (val >> 8);
|
||||
}
|
||||
static inline void putLongLE(unsigned char* buf, long val) {
|
||||
buf[0] = (unsigned char) val;
|
||||
buf[1] = (unsigned char) (val >> 8);
|
||||
buf[2] = (unsigned char) (val >> 16);
|
||||
buf[3] = (unsigned char) (val >> 24);
|
||||
}
|
||||
|
||||
/* defined for Zip archives */
|
||||
enum {
|
||||
kCompressStored = 0, // no compression
|
||||
// shrunk = 1,
|
||||
// reduced 1 = 2,
|
||||
// reduced 2 = 3,
|
||||
// reduced 3 = 4,
|
||||
// reduced 4 = 5,
|
||||
// imploded = 6,
|
||||
// tokenized = 7,
|
||||
kCompressDeflated = 8, // standard deflate
|
||||
// Deflate64 = 9,
|
||||
// lib imploded = 10,
|
||||
// reserved = 11,
|
||||
// bzip2 = 12,
|
||||
};
|
||||
|
||||
/*
|
||||
* Deletion flag. If set, the entry will be removed on the next
|
||||
* call to "flush".
|
||||
*/
|
||||
bool getDeleted(void) const { return mDeleted; }
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Initialize the structure from the file, which is pointing at
|
||||
* our Central Directory entry.
|
||||
*/
|
||||
status_t initFromCDE(FILE* fp);
|
||||
|
||||
/*
|
||||
* Initialize the structure for a new file. We need the filename
|
||||
* and comment so that we can properly size the LFH area. The
|
||||
* filename is mandatory, the comment is optional.
|
||||
*/
|
||||
void initNew(const char* fileName, const char* comment);
|
||||
|
||||
/*
|
||||
* Initialize the structure with the contents of a ZipEntry from
|
||||
* another file.
|
||||
*/
|
||||
status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
|
||||
|
||||
/*
|
||||
* Add some pad bytes to the LFH. We do this by adding or resizing
|
||||
* the "extra" field.
|
||||
*/
|
||||
status_t addPadding(int padding);
|
||||
|
||||
/*
|
||||
* Set information about the data for this entry.
|
||||
*/
|
||||
void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
|
||||
int compressionMethod);
|
||||
|
||||
/*
|
||||
* Set the modification date.
|
||||
*/
|
||||
void setModWhen(time_t when);
|
||||
|
||||
/*
|
||||
* Return the offset of the local file header.
|
||||
*/
|
||||
off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
|
||||
|
||||
/*
|
||||
* Set the offset of the local file header, relative to the start of
|
||||
* the current file.
|
||||
*/
|
||||
void setLFHOffset(off_t offset) {
|
||||
mCDE.mLocalHeaderRelOffset = (long) offset;
|
||||
}
|
||||
|
||||
/* mark for deletion; used by ZipFile::remove() */
|
||||
void setDeleted(void) { mDeleted = true; }
|
||||
|
||||
private:
|
||||
/* these are private and not defined */
|
||||
ZipEntry(const ZipEntry& src);
|
||||
ZipEntry& operator=(const ZipEntry& src);
|
||||
|
||||
/* returns "true" if the CDE and the LFH agree */
|
||||
bool compareHeaders(void) const;
|
||||
void copyCDEtoLFH(void);
|
||||
|
||||
bool mDeleted; // set if entry is pending deletion
|
||||
bool mMarked; // app-defined marker
|
||||
|
||||
/*
|
||||
* Every entry in the Zip archive starts off with one of these.
|
||||
*/
|
||||
class LocalFileHeader {
|
||||
public:
|
||||
LocalFileHeader(void) :
|
||||
mVersionToExtract(0),
|
||||
mGPBitFlag(0),
|
||||
mCompressionMethod(0),
|
||||
mLastModFileTime(0),
|
||||
mLastModFileDate(0),
|
||||
mCRC32(0),
|
||||
mCompressedSize(0),
|
||||
mUncompressedSize(0),
|
||||
mFileNameLength(0),
|
||||
mExtraFieldLength(0),
|
||||
mFileName(NULL),
|
||||
mExtraField(NULL)
|
||||
{}
|
||||
virtual ~LocalFileHeader(void) {
|
||||
delete[] mFileName;
|
||||
delete[] mExtraField;
|
||||
}
|
||||
|
||||
status_t read(FILE* fp);
|
||||
status_t write(FILE* fp);
|
||||
|
||||
// unsigned long mSignature;
|
||||
unsigned short mVersionToExtract;
|
||||
unsigned short mGPBitFlag;
|
||||
unsigned short mCompressionMethod;
|
||||
unsigned short mLastModFileTime;
|
||||
unsigned short mLastModFileDate;
|
||||
unsigned long mCRC32;
|
||||
unsigned long mCompressedSize;
|
||||
unsigned long mUncompressedSize;
|
||||
unsigned short mFileNameLength;
|
||||
unsigned short mExtraFieldLength;
|
||||
unsigned char* mFileName;
|
||||
unsigned char* mExtraField;
|
||||
|
||||
enum {
|
||||
kSignature = 0x04034b50,
|
||||
kLFHLen = 30, // LocalFileHdr len, excl. var fields
|
||||
};
|
||||
|
||||
void dump(void) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Every entry in the Zip archive has one of these in the "central
|
||||
* directory" at the end of the file.
|
||||
*/
|
||||
class CentralDirEntry {
|
||||
public:
|
||||
CentralDirEntry(void) :
|
||||
mVersionMadeBy(0),
|
||||
mVersionToExtract(0),
|
||||
mGPBitFlag(0),
|
||||
mCompressionMethod(0),
|
||||
mLastModFileTime(0),
|
||||
mLastModFileDate(0),
|
||||
mCRC32(0),
|
||||
mCompressedSize(0),
|
||||
mUncompressedSize(0),
|
||||
mFileNameLength(0),
|
||||
mExtraFieldLength(0),
|
||||
mFileCommentLength(0),
|
||||
mDiskNumberStart(0),
|
||||
mInternalAttrs(0),
|
||||
mExternalAttrs(0),
|
||||
mLocalHeaderRelOffset(0),
|
||||
mFileName(NULL),
|
||||
mExtraField(NULL),
|
||||
mFileComment(NULL)
|
||||
{}
|
||||
virtual ~CentralDirEntry(void) {
|
||||
delete[] mFileName;
|
||||
delete[] mExtraField;
|
||||
delete[] mFileComment;
|
||||
}
|
||||
|
||||
status_t read(FILE* fp);
|
||||
status_t write(FILE* fp);
|
||||
|
||||
// unsigned long mSignature;
|
||||
unsigned short mVersionMadeBy;
|
||||
unsigned short mVersionToExtract;
|
||||
unsigned short mGPBitFlag;
|
||||
unsigned short mCompressionMethod;
|
||||
unsigned short mLastModFileTime;
|
||||
unsigned short mLastModFileDate;
|
||||
unsigned long mCRC32;
|
||||
unsigned long mCompressedSize;
|
||||
unsigned long mUncompressedSize;
|
||||
unsigned short mFileNameLength;
|
||||
unsigned short mExtraFieldLength;
|
||||
unsigned short mFileCommentLength;
|
||||
unsigned short mDiskNumberStart;
|
||||
unsigned short mInternalAttrs;
|
||||
unsigned long mExternalAttrs;
|
||||
unsigned long mLocalHeaderRelOffset;
|
||||
unsigned char* mFileName;
|
||||
unsigned char* mExtraField;
|
||||
unsigned char* mFileComment;
|
||||
|
||||
void dump(void) const;
|
||||
|
||||
enum {
|
||||
kSignature = 0x02014b50,
|
||||
kCDELen = 46, // CentralDirEnt len, excl. var fields
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
//kDataDescriptorSignature = 0x08074b50, // currently unused
|
||||
kDataDescriptorLen = 16, // four 32-bit fields
|
||||
|
||||
kDefaultVersion = 20, // need deflate, nothing much else
|
||||
kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
|
||||
kUsesDataDescr = 0x0008, // GPBitFlag bit 3
|
||||
};
|
||||
|
||||
LocalFileHeader mLFH;
|
||||
CentralDirEntry mCDE;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ZIPENTRY_H
|
269
include/utils/ZipFile.h
Normal file
269
include/utils/ZipFile.h
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// General-purpose Zip archive access. This class allows both reading and
|
||||
// writing to Zip archives, including deletion of existing entries.
|
||||
//
|
||||
#ifndef __LIBS_ZIPFILE_H
|
||||
#define __LIBS_ZIPFILE_H
|
||||
|
||||
#include "ZipEntry.h"
|
||||
#include "Vector.h"
|
||||
#include "Errors.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Manipulate a Zip archive.
|
||||
*
|
||||
* Some changes will not be visible in the until until "flush" is called.
|
||||
*
|
||||
* The correct way to update a file archive is to make all changes to a
|
||||
* copy of the archive in a temporary file, and then unlink/rename over
|
||||
* the original after everything completes. Because we're only interested
|
||||
* in using this for packaging, we don't worry about such things. Crashing
|
||||
* after making changes and before flush() completes could leave us with
|
||||
* an unusable Zip archive.
|
||||
*/
|
||||
class ZipFile {
|
||||
public:
|
||||
ZipFile(void)
|
||||
: mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
|
||||
{}
|
||||
~ZipFile(void) {
|
||||
if (!mReadOnly)
|
||||
flush();
|
||||
if (mZipFp != NULL)
|
||||
fclose(mZipFp);
|
||||
discardEntries();
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a new or existing archive.
|
||||
*/
|
||||
typedef enum {
|
||||
kOpenReadOnly = 0x01,
|
||||
kOpenReadWrite = 0x02,
|
||||
kOpenCreate = 0x04, // create if it doesn't exist
|
||||
kOpenTruncate = 0x08, // if it exists, empty it
|
||||
};
|
||||
status_t open(const char* zipFileName, int flags);
|
||||
|
||||
/*
|
||||
* Add a file to the end of the archive. Specify whether you want the
|
||||
* library to try to store it compressed.
|
||||
*
|
||||
* If "storageName" is specified, the archive will use that instead
|
||||
* of "fileName".
|
||||
*
|
||||
* If there is already an entry with the same name, the call fails.
|
||||
* Existing entries with the same name must be removed first.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const char* fileName, int compressionMethod,
|
||||
ZipEntry** ppEntry)
|
||||
{
|
||||
return add(fileName, fileName, compressionMethod, ppEntry);
|
||||
}
|
||||
status_t add(const char* fileName, const char* storageName,
|
||||
int compressionMethod, ZipEntry** ppEntry)
|
||||
{
|
||||
return addCommon(fileName, NULL, 0, storageName,
|
||||
ZipEntry::kCompressStored,
|
||||
compressionMethod, ppEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a file that is already compressed with gzip.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t addGzip(const char* fileName, const char* storageName,
|
||||
ZipEntry** ppEntry)
|
||||
{
|
||||
return addCommon(fileName, NULL, 0, storageName,
|
||||
ZipEntry::kCompressDeflated,
|
||||
ZipEntry::kCompressDeflated, ppEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a file from an in-memory data buffer.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const void* data, size_t size, const char* storageName,
|
||||
int compressionMethod, ZipEntry** ppEntry)
|
||||
{
|
||||
return addCommon(NULL, data, size, storageName,
|
||||
ZipEntry::kCompressStored,
|
||||
compressionMethod, ppEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an entry by copying it from another zip file. If "padding" is
|
||||
* nonzero, the specified number of bytes will be added to the "extra"
|
||||
* field in the header.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
|
||||
int padding, ZipEntry** ppEntry);
|
||||
|
||||
/*
|
||||
* Mark an entry as having been removed. It is not actually deleted
|
||||
* from the archive or our internal data structures until flush() is
|
||||
* called.
|
||||
*/
|
||||
status_t remove(ZipEntry* pEntry);
|
||||
|
||||
/*
|
||||
* Flush changes. If mNeedCDRewrite is set, this writes the central dir.
|
||||
*/
|
||||
status_t flush(void);
|
||||
|
||||
/*
|
||||
* Expand the data into the buffer provided. The buffer must hold
|
||||
* at least <uncompressed len> bytes. Variation expands directly
|
||||
* to a file.
|
||||
*
|
||||
* Returns "false" if an error was encountered in the compressed data.
|
||||
*/
|
||||
//bool uncompress(const ZipEntry* pEntry, void* buf) const;
|
||||
//bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
|
||||
void* uncompress(const ZipEntry* pEntry);
|
||||
|
||||
/*
|
||||
* Get an entry, by name. Returns NULL if not found.
|
||||
*
|
||||
* Does not return entries pending deletion.
|
||||
*/
|
||||
ZipEntry* getEntryByName(const char* fileName) const;
|
||||
|
||||
/*
|
||||
* Get the Nth entry in the archive.
|
||||
*
|
||||
* This will return an entry that is pending deletion.
|
||||
*/
|
||||
int getNumEntries(void) const { return mEntries.size(); }
|
||||
ZipEntry* getEntryByIndex(int idx) const;
|
||||
|
||||
private:
|
||||
/* these are private and not defined */
|
||||
ZipFile(const ZipFile& src);
|
||||
ZipFile& operator=(const ZipFile& src);
|
||||
|
||||
class EndOfCentralDir {
|
||||
public:
|
||||
EndOfCentralDir(void) :
|
||||
mDiskNumber(0),
|
||||
mDiskWithCentralDir(0),
|
||||
mNumEntries(0),
|
||||
mTotalNumEntries(0),
|
||||
mCentralDirSize(0),
|
||||
mCentralDirOffset(0),
|
||||
mCommentLen(0),
|
||||
mComment(NULL)
|
||||
{}
|
||||
virtual ~EndOfCentralDir(void) {
|
||||
delete[] mComment;
|
||||
}
|
||||
|
||||
status_t readBuf(const unsigned char* buf, int len);
|
||||
status_t write(FILE* fp);
|
||||
|
||||
//unsigned long mSignature;
|
||||
unsigned short mDiskNumber;
|
||||
unsigned short mDiskWithCentralDir;
|
||||
unsigned short mNumEntries;
|
||||
unsigned short mTotalNumEntries;
|
||||
unsigned long mCentralDirSize;
|
||||
unsigned long mCentralDirOffset; // offset from first disk
|
||||
unsigned short mCommentLen;
|
||||
unsigned char* mComment;
|
||||
|
||||
enum {
|
||||
kSignature = 0x06054b50,
|
||||
kEOCDLen = 22, // EndOfCentralDir len, excl. comment
|
||||
|
||||
kMaxCommentLen = 65535, // longest possible in ushort
|
||||
kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
|
||||
|
||||
};
|
||||
|
||||
void dump(void) const;
|
||||
};
|
||||
|
||||
|
||||
/* read all entries in the central dir */
|
||||
status_t readCentralDir(void);
|
||||
|
||||
/* crunch deleted entries out */
|
||||
status_t crunchArchive(void);
|
||||
|
||||
/* clean up mEntries */
|
||||
void discardEntries(void);
|
||||
|
||||
/* common handler for all "add" functions */
|
||||
status_t addCommon(const char* fileName, const void* data, size_t size,
|
||||
const char* storageName, int sourceType, int compressionMethod,
|
||||
ZipEntry** ppEntry);
|
||||
|
||||
/* copy all of "srcFp" into "dstFp" */
|
||||
status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
|
||||
/* copy all of "data" into "dstFp" */
|
||||
status_t copyDataToFp(FILE* dstFp,
|
||||
const void* data, size_t size, unsigned long* pCRC32);
|
||||
/* copy some of "srcFp" into "dstFp" */
|
||||
status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
|
||||
unsigned long* pCRC32);
|
||||
/* like memmove(), but on parts of a single file */
|
||||
status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
|
||||
/* compress all of "srcFp" into "dstFp", using Deflate */
|
||||
status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
|
||||
const void* data, size_t size, unsigned long* pCRC32);
|
||||
|
||||
/* get modification date from a file descriptor */
|
||||
time_t getModTime(int fd);
|
||||
|
||||
/*
|
||||
* We use stdio FILE*, which gives us buffering but makes dealing
|
||||
* with files >2GB awkward. Until we support Zip64, we're fine.
|
||||
*/
|
||||
FILE* mZipFp; // Zip file pointer
|
||||
|
||||
/* one of these per file */
|
||||
EndOfCentralDir mEOCD;
|
||||
|
||||
/* did we open this read-only? */
|
||||
bool mReadOnly;
|
||||
|
||||
/* set this when we trash the central dir */
|
||||
bool mNeedCDRewrite;
|
||||
|
||||
/*
|
||||
* One ZipEntry per entry in the zip file. I'm using pointers instead
|
||||
* of objects because it's easier than making operator= work for the
|
||||
* classes and sub-classes.
|
||||
*/
|
||||
Vector<ZipEntry*> mEntries;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ZIPFILE_H
|
59
include/utils/ZipFileCRO.h
Normal file
59
include/utils/ZipFileCRO.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// C API for ead-only access to Zip archives, with minimal heap allocation.
|
||||
//
|
||||
#ifndef __LIBS_ZIPFILECRO_H
|
||||
#define __LIBS_ZIPFILECRO_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Trivial typedef to ensure that ZipFileCRO is not treated as a simple integer.
|
||||
*/
|
||||
typedef void* ZipFileCRO;
|
||||
|
||||
/*
|
||||
* Trivial typedef to ensure that ZipEntryCRO is not treated as a simple
|
||||
* integer. We use NULL to indicate an invalid value.
|
||||
*/
|
||||
typedef void* ZipEntryCRO;
|
||||
|
||||
extern ZipFileCRO ZipFileXRO_open(const char* path);
|
||||
|
||||
extern void ZipFileCRO_destroy(ZipFileCRO zip);
|
||||
|
||||
extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip,
|
||||
const char* fileName);
|
||||
|
||||
extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
|
||||
int* pMethod, long* pUncompLen,
|
||||
long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
|
||||
|
||||
extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__LIBS_ZIPFILECRO_H*/
|
222
include/utils/ZipFileRO.h
Normal file
222
include/utils/ZipFileRO.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Read-only access to Zip archives, with minimal heap allocation.
|
||||
//
|
||||
// This is similar to the more-complete ZipFile class, but no attempt
|
||||
// has been made to make them interchangeable. This class operates under
|
||||
// a very different set of assumptions and constraints.
|
||||
//
|
||||
#ifndef __LIBS_ZIPFILERO_H
|
||||
#define __LIBS_ZIPFILERO_H
|
||||
|
||||
#include "Errors.h"
|
||||
#include "FileMap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Trivial typedef to ensure that ZipEntryRO is not treated as a simple
|
||||
* integer. We use NULL to indicate an invalid value.
|
||||
*/
|
||||
typedef void* ZipEntryRO;
|
||||
|
||||
/*
|
||||
* Open a Zip archive for reading.
|
||||
*
|
||||
* We want "open" and "find entry by name" to be fast operations, and we
|
||||
* want to use as little memory as possible. We memory-map the file,
|
||||
* and load a hash table with pointers to the filenames (which aren't
|
||||
* null-terminated). The other fields are at a fixed offset from the
|
||||
* filename, so we don't need to extract those (but we do need to byte-read
|
||||
* and endian-swap them every time we want them).
|
||||
*
|
||||
* To speed comparisons when doing a lookup by name, we could make the mapping
|
||||
* "private" (copy-on-write) and null-terminate the filenames after verifying
|
||||
* the record structure. However, this requires a private mapping of
|
||||
* every page that the Central Directory touches. Easier to tuck a copy
|
||||
* of the string length into the hash table entry.
|
||||
*/
|
||||
class ZipFileRO {
|
||||
public:
|
||||
ZipFileRO()
|
||||
: mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL)
|
||||
{}
|
||||
~ZipFileRO() {
|
||||
free(mHashTable);
|
||||
if (mFileMap)
|
||||
mFileMap->release();
|
||||
if (mFd >= 0)
|
||||
close(mFd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open an archive.
|
||||
*/
|
||||
status_t open(const char* zipFileName);
|
||||
|
||||
/*
|
||||
* Find an entry, by name. Returns the entry identifier, or NULL if
|
||||
* not found.
|
||||
*
|
||||
* If two entries have the same name, one will be chosen at semi-random.
|
||||
*/
|
||||
ZipEntryRO findEntryByName(const char* fileName) const;
|
||||
|
||||
/*
|
||||
* Return the #of entries in the Zip archive.
|
||||
*/
|
||||
int getNumEntries(void) const {
|
||||
return mNumEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the Nth entry. Zip file entries are not stored in sorted
|
||||
* order, and updated entries may appear at the end, so anyone walking
|
||||
* the archive needs to avoid making ordering assumptions. We take
|
||||
* that further by returning the Nth non-empty entry in the hash table
|
||||
* rather than the Nth entry in the archive.
|
||||
*
|
||||
* Valid values are [0..numEntries).
|
||||
*
|
||||
* [This is currently O(n). If it needs to be fast we can allocate an
|
||||
* additional data structure or provide an iterator interface.]
|
||||
*/
|
||||
ZipEntryRO findEntryByIndex(int idx) const;
|
||||
|
||||
/*
|
||||
* Copy the filename into the supplied buffer. Returns 0 on success,
|
||||
* -1 if "entry" is invalid, or the filename length if it didn't fit. The
|
||||
* length, and the returned string, include the null-termination.
|
||||
*/
|
||||
int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const;
|
||||
|
||||
/*
|
||||
* Get the vital stats for an entry. Pass in NULL pointers for anything
|
||||
* you don't need.
|
||||
*
|
||||
* "*pOffset" holds the Zip file offset of the entry's data.
|
||||
*
|
||||
* Returns "false" if "entry" is bogus or if the data in the Zip file
|
||||
* appears to be bad.
|
||||
*/
|
||||
bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
|
||||
long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
|
||||
|
||||
/*
|
||||
* Create a new FileMap object that maps a subset of the archive. For
|
||||
* an uncompressed entry this effectively provides a pointer to the
|
||||
* actual data, for a compressed entry this provides the input buffer
|
||||
* for inflate().
|
||||
*/
|
||||
FileMap* createEntryFileMap(ZipEntryRO entry) const;
|
||||
|
||||
/*
|
||||
* Uncompress the data into a buffer. Depending on the compression
|
||||
* format, this is either an "inflate" operation or a memcpy.
|
||||
*
|
||||
* Use "uncompLen" from getEntryInfo() to determine the required
|
||||
* buffer size.
|
||||
*
|
||||
* Returns "true" on success.
|
||||
*/
|
||||
bool uncompressEntry(ZipEntryRO entry, void* buffer) const;
|
||||
|
||||
/*
|
||||
* Uncompress the data to an open file descriptor.
|
||||
*/
|
||||
bool uncompressEntry(ZipEntryRO entry, int fd) const;
|
||||
|
||||
/* Zip compression methods we support */
|
||||
enum {
|
||||
kCompressStored = 0, // no compression
|
||||
kCompressDeflated = 8, // standard deflate
|
||||
};
|
||||
|
||||
/*
|
||||
* Utility function: uncompress deflated data, buffer to buffer.
|
||||
*/
|
||||
static bool inflateBuffer(void* outBuf, const void* inBuf,
|
||||
long uncompLen, long compLen);
|
||||
|
||||
/*
|
||||
* Utility function: uncompress deflated data, buffer to fd.
|
||||
*/
|
||||
static bool inflateBuffer(int fd, const void* inBuf,
|
||||
long uncompLen, long compLen);
|
||||
|
||||
/*
|
||||
* Some basic functions for raw data manipulation. "LE" means
|
||||
* Little Endian.
|
||||
*/
|
||||
static inline unsigned short get2LE(const unsigned char* buf) {
|
||||
return buf[0] | (buf[1] << 8);
|
||||
}
|
||||
static inline unsigned long get4LE(const unsigned char* buf) {
|
||||
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
}
|
||||
|
||||
private:
|
||||
/* these are private and not defined */
|
||||
ZipFileRO(const ZipFileRO& src);
|
||||
ZipFileRO& operator=(const ZipFileRO& src);
|
||||
|
||||
/* parse the archive, prepping internal structures */
|
||||
bool parseZipArchive(void);
|
||||
|
||||
/* add a new entry to the hash table */
|
||||
void addToHash(const char* str, int strLen, unsigned int hash);
|
||||
|
||||
/* compute string hash code */
|
||||
static unsigned int computeHash(const char* str, int len);
|
||||
|
||||
/* convert a ZipEntryRO back to a hash table index */
|
||||
int entryToIndex(const ZipEntryRO entry) const;
|
||||
|
||||
/*
|
||||
* One entry in the hash table.
|
||||
*/
|
||||
typedef struct HashEntry {
|
||||
const char* name;
|
||||
unsigned short nameLen;
|
||||
//unsigned int hash;
|
||||
} HashEntry;
|
||||
|
||||
/* open Zip archive */
|
||||
int mFd;
|
||||
|
||||
/* mapped file */
|
||||
FileMap* mFileMap;
|
||||
|
||||
/* number of entries in the Zip archive */
|
||||
int mNumEntries;
|
||||
|
||||
/*
|
||||
* We know how many entries are in the Zip archive, so we have a
|
||||
* fixed-size hash table. We probe for an empty slot.
|
||||
*/
|
||||
int mHashTableSize;
|
||||
HashEntry* mHashTable;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif /*__LIBS_ZIPFILERO_H*/
|
67
include/utils/ZipUtils.h
Normal file
67
include/utils/ZipUtils.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Miscellaneous zip/gzip utility functions.
|
||||
//
|
||||
#ifndef __LIBS_ZIPUTILS_H
|
||||
#define __LIBS_ZIPUTILS_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Container class for utility functions, primarily for namespace reasons.
|
||||
*/
|
||||
class ZipUtils {
|
||||
public:
|
||||
/*
|
||||
* General utility function for uncompressing "deflate" data from a file
|
||||
* to a buffer.
|
||||
*/
|
||||
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
|
||||
long compressedLen);
|
||||
static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
|
||||
long compressedLen);
|
||||
|
||||
/*
|
||||
* Someday we might want to make this generic and handle bzip2 ".bz2"
|
||||
* files too.
|
||||
*
|
||||
* We could declare gzip to be a sub-class of zip that has exactly
|
||||
* one always-compressed entry, but we currently want to treat Zip
|
||||
* and gzip as distinct, so there's no value.
|
||||
*
|
||||
* The zlib library has some gzip utilities, but it has no interface
|
||||
* for extracting the uncompressed length of the file (you do *not*
|
||||
* want to gzseek to the end).
|
||||
*
|
||||
* Pass in a seeked file pointer for the gzip file. If this is a gzip
|
||||
* file, we set our return values appropriately and return "true" with
|
||||
* the file seeked to the start of the compressed data.
|
||||
*/
|
||||
static bool examineGzip(FILE* fp, int* pCompressionMethod,
|
||||
long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32);
|
||||
|
||||
private:
|
||||
ZipUtils() {}
|
||||
~ZipUtils() {}
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif /*__LIBS_ZIPUTILS_H*/
|
41
include/utils/ashmem.h
Normal file
41
include/utils/ashmem.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* utils/ashmem.h
|
||||
**
|
||||
** Copyright 2008 The Android Open Source Project
|
||||
**
|
||||
** This file is dual licensed. It may be redistributed and/or modified
|
||||
** under the terms of the Apache 2.0 License OR version 2 of the GNU
|
||||
** General Public License.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_ASHMEM_H
|
||||
#define _UTILS_ASHMEM_H
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define ASHMEM_NAME_LEN 256
|
||||
|
||||
#define ASHMEM_NAME_DEF "dev/ashmem"
|
||||
|
||||
/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
|
||||
#define ASHMEM_NOT_REAPED 0
|
||||
#define ASHMEM_WAS_REAPED 1
|
||||
|
||||
/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
|
||||
#define ASHMEM_NOW_UNPINNED 0
|
||||
#define ASHMEM_NOW_PINNED 1
|
||||
|
||||
#define __ASHMEMIOC 0x77
|
||||
|
||||
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
|
||||
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
|
||||
#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
|
||||
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
|
||||
#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
|
||||
#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
|
||||
#define ASHMEM_PIN _IO(__ASHMEMIOC, 7)
|
||||
#define ASHMEM_UNPIN _IO(__ASHMEMIOC, 8)
|
||||
#define ASHMEM_ISPINNED _IO(__ASHMEMIOC, 9)
|
||||
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
|
||||
|
||||
#endif /* _UTILS_ASHMEM_H */
|
28
include/utils/executablepath.h
Normal file
28
include/utils/executablepath.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 _UTILS_EXECUTABLEPATH_H
|
||||
#define _UTILS_EXECUTABLEPATH_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// returns the path to this executable
|
||||
#if __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
void executablepath(char s[PATH_MAX]);
|
||||
|
||||
#endif // _UTILS_EXECUTABLEPATH_H
|
103
include/utils/inet_address.h
Normal file
103
include/utils/inet_address.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Internet address classes. Modeled after Java classes.
|
||||
//
|
||||
#ifndef _RUNTIME_INET_ADDRESS_H
|
||||
#define _RUNTIME_INET_ADDRESS_H
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
#error DO NOT USE THIS FILE IN THE DEVICE BUILD
|
||||
#endif
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* This class holds Internet addresses. Perhaps more useful is its
|
||||
* ability to look up addresses by name.
|
||||
*
|
||||
* Invoke one of the static factory methods to create a new object.
|
||||
*/
|
||||
class InetAddress {
|
||||
public:
|
||||
virtual ~InetAddress(void);
|
||||
|
||||
// create from w.x.y.z or foo.bar.com notation
|
||||
static InetAddress* getByName(const char* host);
|
||||
|
||||
// copy-construction
|
||||
InetAddress(const InetAddress& orig);
|
||||
|
||||
const void* getAddress(void) const { return mAddress; }
|
||||
int getAddressLength(void) const { return mLength; }
|
||||
const char* getHostName(void) const { return mName; }
|
||||
|
||||
private:
|
||||
InetAddress(void);
|
||||
// assignment (private)
|
||||
InetAddress& operator=(const InetAddress& addr);
|
||||
|
||||
// use a void* here so we don't have to expose actual socket headers
|
||||
void* mAddress; // this is really a ptr to sockaddr_in
|
||||
int mLength;
|
||||
char* mName;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Base class for socket addresses.
|
||||
*/
|
||||
class SocketAddress {
|
||||
public:
|
||||
SocketAddress() {}
|
||||
virtual ~SocketAddress() {}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Internet address class. This combines an InetAddress with a port.
|
||||
*/
|
||||
class InetSocketAddress : public SocketAddress {
|
||||
public:
|
||||
InetSocketAddress() :
|
||||
mAddress(0), mPort(-1)
|
||||
{}
|
||||
~InetSocketAddress(void) {
|
||||
delete mAddress;
|
||||
}
|
||||
|
||||
// Create an address with a host wildcard (useful for servers).
|
||||
bool create(int port);
|
||||
// Create an address with the specified host and port.
|
||||
bool create(const InetAddress* addr, int port);
|
||||
// Create an address with the specified host and port. Does the
|
||||
// hostname lookup.
|
||||
bool create(const char* host, int port);
|
||||
|
||||
const InetAddress* getAddress(void) const { return mAddress; }
|
||||
const int getPort(void) const { return mPort; }
|
||||
const char* getHostName(void) const { return mAddress->getHostName(); }
|
||||
|
||||
private:
|
||||
InetAddress* mAddress;
|
||||
int mPort;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // _RUNTIME_INET_ADDRESS_H
|
93
include/utils/misc.h
Normal file
93
include/utils/misc.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Handy utility functions and portability code.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_MISC_H
|
||||
#define _LIBS_UTILS_MISC_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include "utils/Endian.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/* get #of elements in a static array */
|
||||
#ifndef NELEM
|
||||
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make a copy of the string, using "new[]" instead of "malloc". Free the
|
||||
* string with delete[].
|
||||
*
|
||||
* Returns NULL if "str" is NULL.
|
||||
*/
|
||||
char* strdupNew(const char* str);
|
||||
|
||||
/*
|
||||
* Concatenate an argument vector into a single string. If argc is >= 0
|
||||
* it will be used; if it's < 0 then the last element in the arg vector
|
||||
* must be NULL.
|
||||
*
|
||||
* This inserts a space between each argument.
|
||||
*
|
||||
* This does not automatically add double quotes around arguments with
|
||||
* spaces in them. This practice is necessary for Win32, because Win32's
|
||||
* CreateProcess call is stupid.
|
||||
*
|
||||
* The caller should delete[] the returned string.
|
||||
*/
|
||||
char* concatArgv(int argc, const char* const argv[]);
|
||||
|
||||
/*
|
||||
* Count up the number of arguments in "argv". The count does not include
|
||||
* the final NULL entry.
|
||||
*/
|
||||
int countArgv(const char* const argv[]);
|
||||
|
||||
/*
|
||||
* Some utility functions for working with files. These could be made
|
||||
* part of a "File" class.
|
||||
*/
|
||||
typedef enum FileType {
|
||||
kFileTypeUnknown = 0,
|
||||
kFileTypeNonexistent, // i.e. ENOENT
|
||||
kFileTypeRegular,
|
||||
kFileTypeDirectory,
|
||||
kFileTypeCharDev,
|
||||
kFileTypeBlockDev,
|
||||
kFileTypeFifo,
|
||||
kFileTypeSymlink,
|
||||
kFileTypeSocket,
|
||||
} FileType;
|
||||
/* get the file's type; follows symlinks */
|
||||
FileType getFileType(const char* fileName);
|
||||
/* get the file's modification date; returns -1 w/errno set on failure */
|
||||
time_t getFileModDate(const char* fileName);
|
||||
|
||||
/*
|
||||
* Round up to the nearest power of 2. Handy for hash tables.
|
||||
*/
|
||||
unsigned int roundUpPower2(unsigned int val);
|
||||
|
||||
void strreverse(char* begin, char* end);
|
||||
void k_itoa(int value, char* str, int base);
|
||||
char* itoa(int val, int base);
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // _LIBS_UTILS_MISC_H
|
50
include/utils/ported.h
Normal file
50
include/utils/ported.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Standard functions ported to the current platform. Note these are NOT
|
||||
// in the "android" namespace.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_PORTED_H
|
||||
#define _LIBS_UTILS_PORTED_H
|
||||
|
||||
#include <sys/time.h> // for timeval
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* library replacement functions */
|
||||
#if defined(NEED_GETTIMEOFDAY)
|
||||
int gettimeofday(struct timeval* tv, struct timezone* tz);
|
||||
#endif
|
||||
#if defined(NEED_USLEEP)
|
||||
void usleep(unsigned long usec);
|
||||
#endif
|
||||
#if defined(NEED_PIPE)
|
||||
int pipe(int filedes[2]);
|
||||
#endif
|
||||
#if defined(NEED_SETENV)
|
||||
int setenv(const char* name, const char* value, int overwrite);
|
||||
void unsetenv(const char* name);
|
||||
char* getenv(const char* name);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _LIBS_UTILS_PORTED_H
|
135
include/utils/string_array.h
Normal file
135
include/utils/string_array.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Sortable array of strings. STL-ish, but STL-free.
|
||||
//
|
||||
#ifndef _LIBS_UTILS_STRING_ARRAY_H
|
||||
#define _LIBS_UTILS_STRING_ARRAY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
//
|
||||
// An expanding array of strings. Add, get, sort, delete.
|
||||
//
|
||||
class StringArray {
|
||||
public:
|
||||
StringArray()
|
||||
: mMax(0), mCurrent(0), mArray(NULL)
|
||||
{}
|
||||
virtual ~StringArray() {
|
||||
for (int i = 0; i < mCurrent; i++)
|
||||
delete[] mArray[i];
|
||||
delete[] mArray;
|
||||
}
|
||||
|
||||
//
|
||||
// Add a string. A copy of the string is made.
|
||||
//
|
||||
bool push_back(const char* str) {
|
||||
if (mCurrent >= mMax) {
|
||||
char** tmp;
|
||||
|
||||
if (mMax == 0)
|
||||
mMax = 16; // initial storage
|
||||
else
|
||||
mMax *= 2;
|
||||
|
||||
tmp = new char*[mMax];
|
||||
if (tmp == NULL)
|
||||
return false;
|
||||
|
||||
memcpy(tmp, mArray, mCurrent * sizeof(char*));
|
||||
delete[] mArray;
|
||||
mArray = tmp;
|
||||
}
|
||||
|
||||
int len = strlen(str);
|
||||
mArray[mCurrent] = new char[len+1];
|
||||
memcpy(mArray[mCurrent], str, len+1);
|
||||
mCurrent++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Delete an entry.
|
||||
//
|
||||
void erase(int idx) {
|
||||
if (idx < 0 || idx >= mCurrent)
|
||||
return;
|
||||
delete[] mArray[idx];
|
||||
if (idx < mCurrent-1) {
|
||||
memmove(&mArray[idx], &mArray[idx+1],
|
||||
(mCurrent-1 - idx) * sizeof(char*));
|
||||
}
|
||||
mCurrent--;
|
||||
}
|
||||
|
||||
//
|
||||
// Sort the array.
|
||||
//
|
||||
void sort(int (*compare)(const void*, const void*)) {
|
||||
qsort(mArray, mCurrent, sizeof(char*), compare);
|
||||
}
|
||||
|
||||
//
|
||||
// Pass this to the sort routine to do an ascending alphabetical sort.
|
||||
//
|
||||
static int cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
|
||||
return strcmp(*(const char**)pstr1, *(const char**)pstr2);
|
||||
}
|
||||
|
||||
//
|
||||
// Get the #of items in the array.
|
||||
//
|
||||
inline int size(void) const { return mCurrent; }
|
||||
|
||||
//
|
||||
// Return entry N.
|
||||
// [should use operator[] here]
|
||||
//
|
||||
const char* getEntry(int idx) const {
|
||||
if (idx < 0 || idx >= mCurrent)
|
||||
return NULL;
|
||||
return mArray[idx];
|
||||
}
|
||||
|
||||
//
|
||||
// Set entry N to specified string.
|
||||
// [should use operator[] here]
|
||||
//
|
||||
void setEntry(int idx, const char* str) {
|
||||
if (idx < 0 || idx >= mCurrent)
|
||||
return;
|
||||
delete[] mArray[idx];
|
||||
int len = strlen(str);
|
||||
mArray[idx] = new char[len+1];
|
||||
memcpy(mArray[idx], str, len+1);
|
||||
}
|
||||
|
||||
private:
|
||||
int mMax;
|
||||
int mCurrent;
|
||||
char** mArray;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // _LIBS_UTILS_STRING_ARRAY_H
|
347
include/utils/threads.h
Normal file
347
include/utils/threads.h
Normal file
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* 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_THREADS_H
|
||||
#define _LIBS_UTILS_THREADS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// C API
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void* android_thread_id_t;
|
||||
|
||||
typedef int (*android_thread_func_t)(void*);
|
||||
|
||||
enum {
|
||||
/*
|
||||
* ***********************************************
|
||||
* ** Keep in sync with android.os.Process.java **
|
||||
* ***********************************************
|
||||
*
|
||||
* This maps directly to the "nice" priorites we use in Android.
|
||||
* A thread priority should be chosen inverse-proportinally 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 = -8,
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// C++ API
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
typedef android_thread_id_t thread_id_t;
|
||||
|
||||
typedef android_thread_func_t thread_func_t;
|
||||
|
||||
enum {
|
||||
PRIORITY_LOWEST = ANDROID_PRIORITY_LOWEST,
|
||||
PRIORITY_BACKGROUND = ANDROID_PRIORITY_BACKGROUND,
|
||||
PRIORITY_NORMAL = ANDROID_PRIORITY_NORMAL,
|
||||
PRIORITY_FOREGROUND = ANDROID_PRIORITY_FOREGROUND,
|
||||
PRIORITY_DISPLAY = ANDROID_PRIORITY_DISPLAY,
|
||||
PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY,
|
||||
PRIORITY_AUDIO = ANDROID_PRIORITY_AUDIO,
|
||||
PRIORITY_URGENT_AUDIO = ANDROID_PRIORITY_URGENT_AUDIO,
|
||||
PRIORITY_HIGHEST = ANDROID_PRIORITY_HIGHEST,
|
||||
PRIORITY_DEFAULT = ANDROID_PRIORITY_DEFAULT,
|
||||
PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE,
|
||||
PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE,
|
||||
};
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
Mutex();
|
||||
Mutex(const char* name);
|
||||
~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) : mpMutex(&mutex) { mutex.lock(); }
|
||||
inline Autolock(Mutex* mutex) : mpMutex(mutex) { mutex->lock(); }
|
||||
inline ~Autolock() { mpMutex->unlock(); }
|
||||
private:
|
||||
Mutex* mpMutex;
|
||||
};
|
||||
|
||||
private:
|
||||
friend class Condition;
|
||||
|
||||
// A mutex cannot be copied
|
||||
Mutex(const Mutex&);
|
||||
Mutex& operator = (const Mutex&);
|
||||
void _init();
|
||||
|
||||
void* mState;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
/*
|
||||
* 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:
|
||||
Condition();
|
||||
~Condition();
|
||||
// Wait on the condition variable. Lock the mutex before calling.
|
||||
status_t wait(Mutex& mutex);
|
||||
// Wait on the condition variable until the given time. Lock the mutex
|
||||
// before calling.
|
||||
status_t wait(Mutex& mutex, nsecs_t abstime);
|
||||
// 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 all threads to continue.
|
||||
void broadcast();
|
||||
|
||||
private:
|
||||
void* mState;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Read/write lock. The resource can have multiple readers or one writer,
|
||||
* but can't be read and written at the same time.
|
||||
*
|
||||
* The same thread should not call a lock function while it already has
|
||||
* a lock. (Should be okay for multiple readers.)
|
||||
*/
|
||||
class ReadWriteLock {
|
||||
public:
|
||||
ReadWriteLock()
|
||||
: mNumReaders(0), mNumWriters(0)
|
||||
{}
|
||||
~ReadWriteLock() {}
|
||||
|
||||
void lockForRead();
|
||||
bool tryLockForRead();
|
||||
void unlockForRead();
|
||||
|
||||
void lockForWrite();
|
||||
bool tryLockForWrite();
|
||||
void unlockForWrite();
|
||||
|
||||
private:
|
||||
int mNumReaders;
|
||||
int mNumWriters;
|
||||
|
||||
Mutex mLock;
|
||||
Condition mReadWaiter;
|
||||
Condition mWriteWaiter;
|
||||
#if defined(PRINT_RENDER_TIMES)
|
||||
DurationTimer mDebugTimer;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This is our spiffy thread object!
|
||||
*/
|
||||
|
||||
class Thread : virtual public RefBase
|
||||
{
|
||||
public:
|
||||
// Create a Thread object, but doesn't create or start the associated
|
||||
// thread. See the run() method.
|
||||
Thread(bool canCallJava = true);
|
||||
virtual ~Thread();
|
||||
|
||||
// Start the thread in threadLoop() which needs to be implemented.
|
||||
virtual status_t run( const char* name = 0,
|
||||
int32_t priority = PRIORITY_DEFAULT,
|
||||
size_t stack = 0);
|
||||
|
||||
// Ask this object's thread to exit. This function is asynchronous, when the
|
||||
// function returns the thread might still be running. Of course, this
|
||||
// function can be called from a different thread.
|
||||
virtual void requestExit();
|
||||
|
||||
// Good place to do one-time initializations
|
||||
virtual status_t readyToRun();
|
||||
|
||||
// Call requestExit() and wait until this object's thread exits.
|
||||
// BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
|
||||
// this function from this object's thread. Will return WOULD_BLOCK in
|
||||
// that case.
|
||||
status_t requestExitAndWait();
|
||||
|
||||
protected:
|
||||
// exitPending() returns true if requestExit() has been called.
|
||||
bool exitPending() const;
|
||||
|
||||
private:
|
||||
// Derived class must implemtent threadLoop(). The thread starts its life
|
||||
// here. There are two ways of using the Thread object:
|
||||
// 1) loop: if threadLoop() returns true, it will be called again if
|
||||
// requestExit() wasn't called.
|
||||
// 2) once: if threadLoop() returns false, the thread will exit upon return.
|
||||
virtual bool threadLoop() = 0;
|
||||
|
||||
private:
|
||||
Thread& operator=(const Thread&);
|
||||
static int _threadLoop(void* user);
|
||||
const bool mCanCallJava;
|
||||
thread_id_t mThread;
|
||||
Mutex mLock;
|
||||
Condition mThreadExitedCondition;
|
||||
status_t mStatus;
|
||||
volatile bool mExitPending;
|
||||
volatile bool mRunning;
|
||||
sp<Thread> mHoldSelf;
|
||||
};
|
||||
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // _LIBS_UTILS_THREADS_H
|
156
libs/utils/Android.mk
Normal file
156
libs/utils/Android.mk
Normal file
|
@ -0,0 +1,156 @@
|
|||
# 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.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# libutils is a little unique: It's built twice, once for the host
|
||||
# and once for the device.
|
||||
|
||||
commonSources:= \
|
||||
Asset.cpp \
|
||||
AssetDir.cpp \
|
||||
AssetManager.cpp \
|
||||
BufferedTextOutput.cpp \
|
||||
CallStack.cpp \
|
||||
Debug.cpp \
|
||||
FileMap.cpp \
|
||||
RefBase.cpp \
|
||||
ResourceTypes.cpp \
|
||||
SharedBuffer.cpp \
|
||||
Static.cpp \
|
||||
StopWatch.cpp \
|
||||
String8.cpp \
|
||||
String16.cpp \
|
||||
SystemClock.cpp \
|
||||
TextOutput.cpp \
|
||||
Threads.cpp \
|
||||
TimerProbe.cpp \
|
||||
Timers.cpp \
|
||||
VectorImpl.cpp \
|
||||
ZipFileCRO.cpp \
|
||||
ZipFileRO.cpp \
|
||||
ZipUtils.cpp \
|
||||
misc.cpp \
|
||||
ported.cpp \
|
||||
LogSocket.cpp
|
||||
|
||||
#
|
||||
# The cpp files listed here do not belong in the device
|
||||
# build. Consult with the swetland before even thinking about
|
||||
# putting them in commonSources.
|
||||
#
|
||||
# They're used by the simulator runtime and by host-side tools like
|
||||
# aapt and the simulator front-end.
|
||||
#
|
||||
hostSources:= \
|
||||
InetAddress.cpp \
|
||||
Pipe.cpp \
|
||||
Socket.cpp \
|
||||
ZipEntry.cpp \
|
||||
ZipFile.cpp
|
||||
|
||||
# For the host
|
||||
# =====================================================
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= $(commonSources) $(hostSources)
|
||||
|
||||
ifeq ($(HOST_OS),linux)
|
||||
# Use the futex based mutex and condition variable
|
||||
# implementation from android-arm because it's shared mem safe
|
||||
LOCAL_SRC_FILES += \
|
||||
futex_synchro.c \
|
||||
executablepath_linux.cpp
|
||||
endif
|
||||
ifeq ($(HOST_OS),darwin)
|
||||
LOCAL_SRC_FILES += \
|
||||
executablepath_darwin.cpp
|
||||
endif
|
||||
|
||||
LOCAL_MODULE:= libutils
|
||||
|
||||
LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
|
||||
LOCAL_C_INCLUDES += external/zlib
|
||||
|
||||
ifeq ($(HOST_OS),windows)
|
||||
ifeq ($(strip $(USE_CYGWIN),),)
|
||||
# Under MinGW, ctype.h doesn't need multi-byte support
|
||||
LOCAL_CFLAGS += -DMB_CUR_MAX=1
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(BUILD_HOST_STATIC_LIBRARY)
|
||||
|
||||
|
||||
|
||||
# For the device
|
||||
# =====================================================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
# we have the common sources, plus some device-specific stuff
|
||||
LOCAL_SRC_FILES:= \
|
||||
$(commonSources) \
|
||||
Binder.cpp \
|
||||
BpBinder.cpp \
|
||||
IInterface.cpp \
|
||||
IMemory.cpp \
|
||||
IPCThreadState.cpp \
|
||||
MemoryDealer.cpp \
|
||||
MemoryBase.cpp \
|
||||
MemoryHeapBase.cpp \
|
||||
MemoryHeapPmem.cpp \
|
||||
Parcel.cpp \
|
||||
ProcessState.cpp \
|
||||
IPermissionController.cpp \
|
||||
IServiceManager.cpp \
|
||||
Unicode.cpp
|
||||
|
||||
ifeq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_SRC_FILES += $(hostSources)
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_OS),linux)
|
||||
# Use the futex based mutex and condition variable
|
||||
# implementation from android-arm because it's shared mem safe
|
||||
LOCAL_SRC_FILES += futex_synchro.c
|
||||
LOCAL_LDLIBS += -lrt -ldl
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/zlib \
|
||||
external/icu4c/common
|
||||
LOCAL_LDLIBS += -lpthread
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libz \
|
||||
liblog \
|
||||
libcutils
|
||||
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
|
||||
# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libdl
|
||||
endif # linux-x86
|
||||
endif # sim
|
||||
|
||||
LOCAL_MODULE:= libutils
|
||||
|
||||
#LOCAL_CFLAGS+=
|
||||
#LOCAL_LDFLAGS:=
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
813
libs/utils/Asset.cpp
Normal file
813
libs/utils/Asset.cpp
Normal file
|
@ -0,0 +1,813 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Provide access to a read-only asset.
|
||||
//
|
||||
|
||||
#define LOG_TAG "asset"
|
||||
//#define NDEBUG 0
|
||||
|
||||
#include <utils/Asset.h>
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/FileMap.h>
|
||||
#include <utils/ZipUtils.h>
|
||||
#include <utils/ZipFileRO.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
static volatile int32_t gCount = 0;
|
||||
|
||||
int32_t Asset::getGlobalCount()
|
||||
{
|
||||
return gCount;
|
||||
}
|
||||
|
||||
Asset::Asset(void)
|
||||
: mAccessMode(ACCESS_UNKNOWN)
|
||||
{
|
||||
int count = android_atomic_inc(&gCount)+1;
|
||||
//LOGI("Creating Asset %p #%d\n", this, count);
|
||||
}
|
||||
|
||||
Asset::~Asset(void)
|
||||
{
|
||||
int count = android_atomic_dec(&gCount);
|
||||
//LOGI("Destroying Asset in %p #%d\n", this, count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new Asset from a file on disk. There is a fair chance that
|
||||
* the file doesn't actually exist.
|
||||
*
|
||||
* We can use "mode" to decide how we want to go about it.
|
||||
*/
|
||||
/*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode)
|
||||
{
|
||||
_FileAsset* pAsset;
|
||||
status_t result;
|
||||
off_t length;
|
||||
int fd;
|
||||
|
||||
fd = open(fileName, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Under Linux, the lseek fails if we actually opened a directory. To
|
||||
* be correct we should test the file type explicitly, but since we
|
||||
* always open things read-only it doesn't really matter, so there's
|
||||
* no value in incurring the extra overhead of an fstat() call.
|
||||
*/
|
||||
length = lseek(fd, 0, SEEK_END);
|
||||
if (length < 0) {
|
||||
::close(fd);
|
||||
return NULL;
|
||||
}
|
||||
(void) lseek(fd, 0, SEEK_SET);
|
||||
|
||||
pAsset = new _FileAsset;
|
||||
result = pAsset->openChunk(fileName, fd, 0, length);
|
||||
if (result != NO_ERROR) {
|
||||
delete pAsset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pAsset->mAccessMode = mode;
|
||||
return pAsset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a new Asset from a compressed file on disk. There is a fair chance
|
||||
* that the file doesn't actually exist.
|
||||
*
|
||||
* We currently support gzip files. We might want to handle .bz2 someday.
|
||||
*/
|
||||
/*static*/ Asset* Asset::createFromCompressedFile(const char* fileName,
|
||||
AccessMode mode)
|
||||
{
|
||||
_CompressedAsset* pAsset;
|
||||
status_t result;
|
||||
off_t fileLen;
|
||||
bool scanResult;
|
||||
long offset;
|
||||
int method;
|
||||
long uncompressedLen, compressedLen;
|
||||
int fd;
|
||||
|
||||
fd = open(fileName, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
fileLen = lseek(fd, 0, SEEK_END);
|
||||
if (fileLen < 0) {
|
||||
::close(fd);
|
||||
return NULL;
|
||||
}
|
||||
(void) lseek(fd, 0, SEEK_SET);
|
||||
|
||||
/* want buffered I/O for the file scan; must dup so fclose() is safe */
|
||||
FILE* fp = fdopen(dup(fd), "rb");
|
||||
if (fp == NULL) {
|
||||
::close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long crc32;
|
||||
scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen,
|
||||
&compressedLen, &crc32);
|
||||
offset = ftell(fp);
|
||||
fclose(fp);
|
||||
if (!scanResult) {
|
||||
LOGD("File '%s' is not in gzip format\n", fileName);
|
||||
::close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pAsset = new _CompressedAsset;
|
||||
result = pAsset->openChunk(fd, offset, method, uncompressedLen,
|
||||
compressedLen);
|
||||
if (result != NO_ERROR) {
|
||||
delete pAsset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pAsset->mAccessMode = mode;
|
||||
return pAsset;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Create a new Asset from part of an open file.
|
||||
*/
|
||||
/*static*/ Asset* Asset::createFromFileSegment(int fd, off_t offset,
|
||||
size_t length, AccessMode mode)
|
||||
{
|
||||
_FileAsset* pAsset;
|
||||
status_t result;
|
||||
|
||||
pAsset = new _FileAsset;
|
||||
result = pAsset->openChunk(NULL, fd, offset, length);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
|
||||
pAsset->mAccessMode = mode;
|
||||
return pAsset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new Asset from compressed data in an open file.
|
||||
*/
|
||||
/*static*/ Asset* Asset::createFromCompressedData(int fd, off_t offset,
|
||||
int compressionMethod, size_t uncompressedLen, size_t compressedLen,
|
||||
AccessMode mode)
|
||||
{
|
||||
_CompressedAsset* pAsset;
|
||||
status_t result;
|
||||
|
||||
pAsset = new _CompressedAsset;
|
||||
result = pAsset->openChunk(fd, offset, compressionMethod,
|
||||
uncompressedLen, compressedLen);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
|
||||
pAsset->mAccessMode = mode;
|
||||
return pAsset;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create a new Asset from a memory mapping.
|
||||
*/
|
||||
/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap,
|
||||
AccessMode mode)
|
||||
{
|
||||
_FileAsset* pAsset;
|
||||
status_t result;
|
||||
|
||||
pAsset = new _FileAsset;
|
||||
result = pAsset->openChunk(dataMap);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
|
||||
pAsset->mAccessMode = mode;
|
||||
return pAsset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new Asset from compressed data in a memory mapping.
|
||||
*/
|
||||
/*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
|
||||
int method, size_t uncompressedLen, AccessMode mode)
|
||||
{
|
||||
_CompressedAsset* pAsset;
|
||||
status_t result;
|
||||
|
||||
pAsset = new _CompressedAsset;
|
||||
result = pAsset->openChunk(dataMap, method, uncompressedLen);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
|
||||
pAsset->mAccessMode = mode;
|
||||
return pAsset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do generic seek() housekeeping. Pass in the offset/whence values from
|
||||
* the seek request, along with the current chunk offset and the chunk
|
||||
* length.
|
||||
*
|
||||
* Returns the new chunk offset, or -1 if the seek is illegal.
|
||||
*/
|
||||
off_t Asset::handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn)
|
||||
{
|
||||
off_t newOffset;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
newOffset = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
newOffset = curPosn + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
newOffset = maxPosn + offset;
|
||||
break;
|
||||
default:
|
||||
LOGW("unexpected whence %d\n", whence);
|
||||
// this was happening due to an off_t size mismatch
|
||||
assert(false);
|
||||
return (off_t) -1;
|
||||
}
|
||||
|
||||
if (newOffset < 0 || newOffset > maxPosn) {
|
||||
LOGW("seek out of range: want %ld, end=%ld\n",
|
||||
(long) newOffset, (long) maxPosn);
|
||||
return (off_t) -1;
|
||||
}
|
||||
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* _FileAsset
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Constructor.
|
||||
*/
|
||||
_FileAsset::_FileAsset(void)
|
||||
: mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor. Release resources.
|
||||
*/
|
||||
_FileAsset::~_FileAsset(void)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Operate on a chunk of an uncompressed file.
|
||||
*
|
||||
* Zero-length chunks are allowed.
|
||||
*/
|
||||
status_t _FileAsset::openChunk(const char* fileName, int fd, off_t offset, size_t length)
|
||||
{
|
||||
assert(mFp == NULL); // no reopen
|
||||
assert(mMap == NULL);
|
||||
assert(fd >= 0);
|
||||
assert(offset >= 0);
|
||||
|
||||
/*
|
||||
* Seek to end to get file length.
|
||||
*/
|
||||
off_t fileLength;
|
||||
fileLength = lseek(fd, 0, SEEK_END);
|
||||
if (fileLength == (off_t) -1) {
|
||||
// probably a bad file descriptor
|
||||
LOGD("failed lseek (errno=%d)\n", errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if ((off_t) (offset + length) > fileLength) {
|
||||
LOGD("start (%ld) + len (%ld) > end (%ld)\n",
|
||||
(long) offset, (long) length, (long) fileLength);
|
||||
return BAD_INDEX;
|
||||
}
|
||||
|
||||
/* after fdopen, the fd will be closed on fclose() */
|
||||
mFp = fdopen(fd, "rb");
|
||||
if (mFp == NULL)
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
mStart = offset;
|
||||
mLength = length;
|
||||
assert(mOffset == 0);
|
||||
|
||||
/* seek the FILE* to the start of chunk */
|
||||
if (fseek(mFp, mStart, SEEK_SET) != 0) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
mFileName = fileName != NULL ? strdup(fileName) : NULL;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the chunk from the map.
|
||||
*/
|
||||
status_t _FileAsset::openChunk(FileMap* dataMap)
|
||||
{
|
||||
assert(mFp == NULL); // no reopen
|
||||
assert(mMap == NULL);
|
||||
assert(dataMap != NULL);
|
||||
|
||||
mMap = dataMap;
|
||||
mStart = -1; // not used
|
||||
mLength = dataMap->getDataLength();
|
||||
assert(mOffset == 0);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a chunk of data.
|
||||
*/
|
||||
ssize_t _FileAsset::read(void* buf, size_t count)
|
||||
{
|
||||
size_t maxLen;
|
||||
size_t actual;
|
||||
|
||||
assert(mOffset >= 0 && mOffset <= mLength);
|
||||
|
||||
if (getAccessMode() == ACCESS_BUFFER) {
|
||||
/*
|
||||
* On first access, read or map the entire file. The caller has
|
||||
* requested buffer access, either because they're going to be
|
||||
* using the buffer or because what they're doing has appropriate
|
||||
* performance needs and access patterns.
|
||||
*/
|
||||
if (mBuf == NULL)
|
||||
getBuffer(false);
|
||||
}
|
||||
|
||||
/* adjust count if we're near EOF */
|
||||
maxLen = mLength - mOffset;
|
||||
if (count > maxLen)
|
||||
count = maxLen;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (mMap != NULL) {
|
||||
/* copy from mapped area */
|
||||
//printf("map read\n");
|
||||
memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
|
||||
actual = count;
|
||||
} else if (mBuf != NULL) {
|
||||
/* copy from buffer */
|
||||
//printf("buf read\n");
|
||||
memcpy(buf, (char*)mBuf + mOffset, count);
|
||||
actual = count;
|
||||
} else {
|
||||
/* read from the file */
|
||||
//printf("file read\n");
|
||||
if (ftell(mFp) != mStart + mOffset) {
|
||||
LOGE("Hosed: %ld != %ld+%ld\n",
|
||||
ftell(mFp), (long) mStart, (long) mOffset);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns 0 on error or eof. We need to use ferror() or feof()
|
||||
* to tell the difference, but we don't currently have those on the
|
||||
* device. However, we know how much data is *supposed* to be in the
|
||||
* file, so if we don't read the full amount we know something is
|
||||
* hosed.
|
||||
*/
|
||||
actual = fread(buf, 1, count, mFp);
|
||||
if (actual == 0) // something failed -- I/O error?
|
||||
return -1;
|
||||
|
||||
assert(actual == count);
|
||||
}
|
||||
|
||||
mOffset += actual;
|
||||
return actual;
|
||||
}
|
||||
|
||||
/*
|
||||
* Seek to a new position.
|
||||
*/
|
||||
off_t _FileAsset::seek(off_t offset, int whence)
|
||||
{
|
||||
off_t newPosn;
|
||||
long actualOffset;
|
||||
|
||||
// compute new position within chunk
|
||||
newPosn = handleSeek(offset, whence, mOffset, mLength);
|
||||
if (newPosn == (off_t) -1)
|
||||
return newPosn;
|
||||
|
||||
actualOffset = (long) (mStart + newPosn);
|
||||
|
||||
if (mFp != NULL) {
|
||||
if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
|
||||
return (off_t) -1;
|
||||
}
|
||||
|
||||
mOffset = actualOffset - mStart;
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the asset.
|
||||
*/
|
||||
void _FileAsset::close(void)
|
||||
{
|
||||
if (mMap != NULL) {
|
||||
mMap->release();
|
||||
mMap = NULL;
|
||||
}
|
||||
if (mBuf != NULL) {
|
||||
delete[] mBuf;
|
||||
mBuf = NULL;
|
||||
}
|
||||
|
||||
if (mFileName != NULL) {
|
||||
free(mFileName);
|
||||
mFileName = NULL;
|
||||
}
|
||||
|
||||
if (mFp != NULL) {
|
||||
// can only be NULL when called from destructor
|
||||
// (otherwise we would never return this object)
|
||||
fclose(mFp);
|
||||
mFp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a read-only pointer to a buffer.
|
||||
*
|
||||
* We can either read the whole thing in or map the relevant piece of
|
||||
* the source file. Ideally a map would be established at a higher
|
||||
* level and we'd be using a different object, but we didn't, so we
|
||||
* deal with it here.
|
||||
*/
|
||||
const void* _FileAsset::getBuffer(bool wordAligned)
|
||||
{
|
||||
/* subsequent requests just use what we did previously */
|
||||
if (mBuf != NULL)
|
||||
return mBuf;
|
||||
if (mMap != NULL) {
|
||||
if (!wordAligned) {
|
||||
return mMap->getDataPtr();
|
||||
}
|
||||
return ensureAlignment(mMap);
|
||||
}
|
||||
|
||||
assert(mFp != NULL);
|
||||
|
||||
if (mLength < kReadVsMapThreshold) {
|
||||
unsigned char* buf;
|
||||
long allocLen;
|
||||
|
||||
/* zero-length files are allowed; not sure about zero-len allocs */
|
||||
/* (works fine with gcc + x86linux) */
|
||||
allocLen = mLength;
|
||||
if (mLength == 0)
|
||||
allocLen = 1;
|
||||
|
||||
buf = new unsigned char[allocLen];
|
||||
if (buf == NULL) {
|
||||
LOGE("alloc of %ld bytes failed\n", (long) allocLen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
|
||||
if (mLength > 0) {
|
||||
long oldPosn = ftell(mFp);
|
||||
fseek(mFp, mStart, SEEK_SET);
|
||||
if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
|
||||
LOGE("failed reading %ld bytes\n", (long) mLength);
|
||||
delete[] buf;
|
||||
return NULL;
|
||||
}
|
||||
fseek(mFp, oldPosn, SEEK_SET);
|
||||
}
|
||||
|
||||
LOGV(" getBuffer: loaded into buffer\n");
|
||||
|
||||
mBuf = buf;
|
||||
return mBuf;
|
||||
} else {
|
||||
FileMap* map;
|
||||
|
||||
map = new FileMap;
|
||||
if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
|
||||
map->release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOGV(" getBuffer: mapped\n");
|
||||
|
||||
mMap = map;
|
||||
if (!wordAligned) {
|
||||
return mMap->getDataPtr();
|
||||
}
|
||||
return ensureAlignment(mMap);
|
||||
}
|
||||
}
|
||||
|
||||
int _FileAsset::openFileDescriptor(off_t* outStart, off_t* outLength) const
|
||||
{
|
||||
if (mMap != NULL) {
|
||||
const char* fname = mMap->getFileName();
|
||||
if (fname == NULL) {
|
||||
fname = mFileName;
|
||||
}
|
||||
if (fname == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*outStart = mMap->getDataOffset();
|
||||
*outLength = mMap->getDataLength();
|
||||
return open(fname, O_RDONLY | O_BINARY);
|
||||
}
|
||||
if (mFileName == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*outStart = mStart;
|
||||
*outLength = mLength;
|
||||
return open(mFileName, O_RDONLY | O_BINARY);
|
||||
}
|
||||
|
||||
const void* _FileAsset::ensureAlignment(FileMap* map)
|
||||
{
|
||||
void* data = map->getDataPtr();
|
||||
if ((((size_t)data)&0x3) == 0) {
|
||||
// We can return this directly if it is aligned on a word
|
||||
// boundary.
|
||||
return data;
|
||||
}
|
||||
// If not aligned on a word boundary, then we need to copy it into
|
||||
// our own buffer.
|
||||
LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength);
|
||||
unsigned char* buf = new unsigned char[mLength];
|
||||
if (buf == NULL) {
|
||||
LOGE("alloc of %ld bytes failed\n", (long) mLength);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, data, mLength);
|
||||
mBuf = buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* _CompressedAsset
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Constructor.
|
||||
*/
|
||||
_CompressedAsset::_CompressedAsset(void)
|
||||
: mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
|
||||
mMap(NULL), mFd(-1), mBuf(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor. Release resources.
|
||||
*/
|
||||
_CompressedAsset::~_CompressedAsset(void)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a chunk of compressed data inside a file.
|
||||
*
|
||||
* This currently just sets up some values and returns. On the first
|
||||
* read, we expand the entire file into a buffer and return data from it.
|
||||
*/
|
||||
status_t _CompressedAsset::openChunk(int fd, off_t offset,
|
||||
int compressionMethod, size_t uncompressedLen, size_t compressedLen)
|
||||
{
|
||||
assert(mFd < 0); // no re-open
|
||||
assert(mMap == NULL);
|
||||
assert(fd >= 0);
|
||||
assert(offset >= 0);
|
||||
assert(compressedLen > 0);
|
||||
|
||||
if (compressionMethod != ZipFileRO::kCompressDeflated) {
|
||||
assert(false);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mStart = offset;
|
||||
mCompressedLen = compressedLen;
|
||||
mUncompressedLen = uncompressedLen;
|
||||
assert(mOffset == 0);
|
||||
mFd = fd;
|
||||
assert(mBuf == NULL);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a chunk of compressed data in a mapped region.
|
||||
*
|
||||
* Nothing is expanded until the first read call.
|
||||
*/
|
||||
status_t _CompressedAsset::openChunk(FileMap* dataMap, int compressionMethod,
|
||||
size_t uncompressedLen)
|
||||
{
|
||||
assert(mFd < 0); // no re-open
|
||||
assert(mMap == NULL);
|
||||
assert(dataMap != NULL);
|
||||
|
||||
if (compressionMethod != ZipFileRO::kCompressDeflated) {
|
||||
assert(false);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mMap = dataMap;
|
||||
mStart = -1; // not used
|
||||
mCompressedLen = dataMap->getDataLength();
|
||||
mUncompressedLen = uncompressedLen;
|
||||
assert(mOffset == 0);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read data from a chunk of compressed data.
|
||||
*
|
||||
* [For now, that's just copying data out of a buffer.]
|
||||
*/
|
||||
ssize_t _CompressedAsset::read(void* buf, size_t count)
|
||||
{
|
||||
size_t maxLen;
|
||||
size_t actual;
|
||||
|
||||
assert(mOffset >= 0 && mOffset <= mUncompressedLen);
|
||||
|
||||
// TODO: if mAccessMode == ACCESS_STREAMING, use zlib more cleverly
|
||||
|
||||
if (mBuf == NULL) {
|
||||
if (getBuffer(false) == NULL)
|
||||
return -1;
|
||||
}
|
||||
assert(mBuf != NULL);
|
||||
|
||||
/* adjust count if we're near EOF */
|
||||
maxLen = mUncompressedLen - mOffset;
|
||||
if (count > maxLen)
|
||||
count = maxLen;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
/* copy from buffer */
|
||||
//printf("comp buf read\n");
|
||||
memcpy(buf, (char*)mBuf + mOffset, count);
|
||||
actual = count;
|
||||
|
||||
mOffset += actual;
|
||||
return actual;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a seek request.
|
||||
*
|
||||
* If we're working in a streaming mode, this is going to be fairly
|
||||
* expensive, because it requires plowing through a bunch of compressed
|
||||
* data.
|
||||
*/
|
||||
off_t _CompressedAsset::seek(off_t offset, int whence)
|
||||
{
|
||||
off_t newPosn;
|
||||
|
||||
// compute new position within chunk
|
||||
newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
|
||||
if (newPosn == (off_t) -1)
|
||||
return newPosn;
|
||||
|
||||
mOffset = newPosn;
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the asset.
|
||||
*/
|
||||
void _CompressedAsset::close(void)
|
||||
{
|
||||
if (mMap != NULL) {
|
||||
mMap->release();
|
||||
mMap = NULL;
|
||||
}
|
||||
if (mBuf != NULL) {
|
||||
delete[] mBuf;
|
||||
mBuf = NULL;
|
||||
}
|
||||
|
||||
if (mFd > 0) {
|
||||
::close(mFd);
|
||||
mFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to a read-only buffer of data.
|
||||
*
|
||||
* The first time this is called, we expand the compressed data into a
|
||||
* buffer.
|
||||
*/
|
||||
const void* _CompressedAsset::getBuffer(bool wordAligned)
|
||||
{
|
||||
unsigned char* buf = NULL;
|
||||
|
||||
if (mBuf != NULL)
|
||||
return mBuf;
|
||||
|
||||
if (mUncompressedLen > UNCOMPRESS_DATA_MAX) {
|
||||
LOGD("Data exceeds UNCOMPRESS_DATA_MAX (%ld vs %d)\n",
|
||||
(long) mUncompressedLen, UNCOMPRESS_DATA_MAX);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a buffer and read the file into it.
|
||||
*/
|
||||
buf = new unsigned char[mUncompressedLen];
|
||||
if (buf == NULL) {
|
||||
LOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (mMap != NULL) {
|
||||
if (!ZipFileRO::inflateBuffer(buf, mMap->getDataPtr(),
|
||||
mUncompressedLen, mCompressedLen))
|
||||
goto bail;
|
||||
} else {
|
||||
assert(mFd >= 0);
|
||||
|
||||
/*
|
||||
* Seek to the start of the compressed data.
|
||||
*/
|
||||
if (lseek(mFd, mStart, SEEK_SET) != mStart)
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* Expand the data into it.
|
||||
*/
|
||||
if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
|
||||
mCompressedLen))
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* success! */
|
||||
mBuf = buf;
|
||||
buf = NULL;
|
||||
|
||||
bail:
|
||||
delete[] buf;
|
||||
return mBuf;
|
||||
}
|
||||
|
66
libs/utils/AssetDir.cpp
Normal file
66
libs/utils/AssetDir.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Provide access to a virtual directory in "asset space". Most of the
|
||||
// implementation is in the header file or in friend functions in
|
||||
// AssetManager.
|
||||
//
|
||||
#include <utils/AssetDir.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
|
||||
/*
|
||||
* Find a matching entry in a vector of FileInfo. Because it's sorted, we
|
||||
* can use a binary search.
|
||||
*
|
||||
* Assumes the vector is sorted in ascending order.
|
||||
*/
|
||||
/*static*/ int AssetDir::FileInfo::findEntry(const SortedVector<FileInfo>* pVector,
|
||||
const String8& fileName)
|
||||
{
|
||||
FileInfo tmpInfo;
|
||||
|
||||
tmpInfo.setFileName(fileName);
|
||||
return pVector->indexOf(tmpInfo);
|
||||
|
||||
#if 0 // don't need this after all (uses 1/2 compares of SortedVector though)
|
||||
int lo, hi, cur;
|
||||
|
||||
lo = 0;
|
||||
hi = pVector->size() -1;
|
||||
while (lo <= hi) {
|
||||
int cmp;
|
||||
|
||||
cur = (hi + lo) / 2;
|
||||
cmp = strcmp(pVector->itemAt(cur).getFileName(), fileName);
|
||||
if (cmp == 0) {
|
||||
/* match, bail */
|
||||
return cur;
|
||||
} else if (cmp < 0) {
|
||||
/* too low */
|
||||
lo = cur + 1;
|
||||
} else {
|
||||
/* too high */
|
||||
hi = cur -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
1637
libs/utils/AssetManager.cpp
Normal file
1637
libs/utils/AssetManager.cpp
Normal file
File diff suppressed because it is too large
Load diff
242
libs/utils/Binder.cpp
Normal file
242
libs/utils/Binder.cpp
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/Binder.h>
|
||||
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/BpBinder.h>
|
||||
#include <utils/IInterface.h>
|
||||
#include <utils/Parcel.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BBinder* IBinder::localBinder()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BpBinder* IBinder::remoteBinder()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IBinder::checkSubclass(const void* /*subclassID*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class BBinder::Extras
|
||||
{
|
||||
public:
|
||||
Mutex mLock;
|
||||
BpBinder::ObjectManager mObjects;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BBinder::BBinder()
|
||||
: mExtras(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
bool BBinder::isBinderAlive() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
status_t BBinder::pingBinder()
|
||||
{
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
String16 BBinder::getInterfaceDescriptor() const
|
||||
{
|
||||
LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
|
||||
return String16();
|
||||
}
|
||||
|
||||
status_t BBinder::transact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
data.setDataPosition(0);
|
||||
|
||||
status_t err = NO_ERROR;
|
||||
switch (code) {
|
||||
case PING_TRANSACTION:
|
||||
reply->writeInt32(pingBinder());
|
||||
break;
|
||||
default:
|
||||
err = onTransact(code, data, reply, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply != NULL) {
|
||||
reply->setDataPosition(0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t BBinder::linkToDeath(
|
||||
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
|
||||
{
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
status_t BBinder::unlinkToDeath(
|
||||
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
|
||||
wp<DeathRecipient>* outRecipient)
|
||||
{
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
status_t BBinder::dump(int fd, const Vector<String16>& args)
|
||||
{
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void BBinder::attachObject(
|
||||
const void* objectID, void* object, void* cleanupCookie,
|
||||
object_cleanup_func func)
|
||||
{
|
||||
Extras* e = mExtras;
|
||||
|
||||
if (!e) {
|
||||
e = new Extras;
|
||||
if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
|
||||
reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
|
||||
delete e;
|
||||
e = mExtras;
|
||||
}
|
||||
if (e == 0) return; // out of memory
|
||||
}
|
||||
|
||||
AutoMutex _l(e->mLock);
|
||||
e->mObjects.attach(objectID, object, cleanupCookie, func);
|
||||
}
|
||||
|
||||
void* BBinder::findObject(const void* objectID) const
|
||||
{
|
||||
Extras* e = mExtras;
|
||||
if (!e) return NULL;
|
||||
|
||||
AutoMutex _l(e->mLock);
|
||||
return e->mObjects.find(objectID);
|
||||
}
|
||||
|
||||
void BBinder::detachObject(const void* objectID)
|
||||
{
|
||||
Extras* e = mExtras;
|
||||
if (!e) return;
|
||||
|
||||
AutoMutex _l(e->mLock);
|
||||
e->mObjects.detach(objectID);
|
||||
}
|
||||
|
||||
BBinder* BBinder::localBinder()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
BBinder::~BBinder()
|
||||
{
|
||||
if (mExtras) delete mExtras;
|
||||
}
|
||||
|
||||
|
||||
status_t BBinder::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch (code) {
|
||||
case INTERFACE_TRANSACTION:
|
||||
reply->writeString16(getInterfaceDescriptor());
|
||||
return NO_ERROR;
|
||||
|
||||
case DUMP_TRANSACTION: {
|
||||
int fd = data.readFileDescriptor();
|
||||
int argc = data.readInt32();
|
||||
Vector<String16> args;
|
||||
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
|
||||
args.add(data.readString16());
|
||||
}
|
||||
return dump(fd, args);
|
||||
}
|
||||
default:
|
||||
return UNKNOWN_TRANSACTION;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum {
|
||||
// This is used to transfer ownership of the remote binder from
|
||||
// the BpRefBase object holding it (when it is constructed), to the
|
||||
// owner of the BpRefBase object when it first acquires that BpRefBase.
|
||||
kRemoteAcquired = 0x00000001
|
||||
};
|
||||
|
||||
BpRefBase::BpRefBase(const sp<IBinder>& o)
|
||||
: mRemote(o.get()), mRefs(NULL), mState(0)
|
||||
{
|
||||
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
|
||||
|
||||
if (mRemote) {
|
||||
mRemote->incStrong(this); // Removed on first IncStrong().
|
||||
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
|
||||
}
|
||||
}
|
||||
|
||||
BpRefBase::~BpRefBase()
|
||||
{
|
||||
if (mRemote) {
|
||||
if (!(mState&kRemoteAcquired)) {
|
||||
mRemote->decStrong(this);
|
||||
}
|
||||
mRefs->decWeak(this);
|
||||
}
|
||||
}
|
||||
|
||||
void BpRefBase::onFirstRef()
|
||||
{
|
||||
android_atomic_or(kRemoteAcquired, &mState);
|
||||
}
|
||||
|
||||
void BpRefBase::onLastStrongRef(const void* id)
|
||||
{
|
||||
if (mRemote) {
|
||||
mRemote->decStrong(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
|
||||
{
|
||||
return mRemote ? mRefs->attemptIncStrong(this) : false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
348
libs/utils/BpBinder.cpp
Normal file
348
libs/utils/BpBinder.cpp
Normal file
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "BpBinder"
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include <utils/BpBinder.h>
|
||||
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//#undef LOGV
|
||||
//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BpBinder::ObjectManager::ObjectManager()
|
||||
{
|
||||
}
|
||||
|
||||
BpBinder::ObjectManager::~ObjectManager()
|
||||
{
|
||||
kill();
|
||||
}
|
||||
|
||||
void BpBinder::ObjectManager::attach(
|
||||
const void* objectID, void* object, void* cleanupCookie,
|
||||
IBinder::object_cleanup_func func)
|
||||
{
|
||||
entry_t e;
|
||||
e.object = object;
|
||||
e.cleanupCookie = cleanupCookie;
|
||||
e.func = func;
|
||||
|
||||
if (mObjects.indexOfKey(objectID) >= 0) {
|
||||
LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
|
||||
objectID, this, object);
|
||||
return;
|
||||
}
|
||||
|
||||
mObjects.add(objectID, e);
|
||||
}
|
||||
|
||||
void* BpBinder::ObjectManager::find(const void* objectID) const
|
||||
{
|
||||
const ssize_t i = mObjects.indexOfKey(objectID);
|
||||
if (i < 0) return NULL;
|
||||
return mObjects.valueAt(i).object;
|
||||
}
|
||||
|
||||
void BpBinder::ObjectManager::detach(const void* objectID)
|
||||
{
|
||||
mObjects.removeItem(objectID);
|
||||
}
|
||||
|
||||
void BpBinder::ObjectManager::kill()
|
||||
{
|
||||
const size_t N = mObjects.size();
|
||||
LOGV("Killing %d objects in manager %p", N, this);
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const entry_t& e = mObjects.valueAt(i);
|
||||
if (e.func != NULL) {
|
||||
e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
|
||||
}
|
||||
}
|
||||
|
||||
mObjects.clear();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BpBinder::BpBinder(int32_t handle)
|
||||
: mHandle(handle)
|
||||
, mAlive(1)
|
||||
, mObitsSent(0)
|
||||
, mObituaries(NULL)
|
||||
{
|
||||
LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
|
||||
|
||||
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
|
||||
IPCThreadState::self()->incWeakHandle(handle);
|
||||
}
|
||||
|
||||
String16 BpBinder::getInterfaceDescriptor() const
|
||||
{
|
||||
String16 res;
|
||||
Parcel send, reply;
|
||||
status_t err = const_cast<BpBinder*>(this)->transact(
|
||||
INTERFACE_TRANSACTION, send, &reply);
|
||||
if (err == NO_ERROR) {
|
||||
res = reply.readString16();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool BpBinder::isBinderAlive() const
|
||||
{
|
||||
return mAlive != 0;
|
||||
}
|
||||
|
||||
status_t BpBinder::pingBinder()
|
||||
{
|
||||
Parcel send;
|
||||
Parcel reply;
|
||||
status_t err = transact(PING_TRANSACTION, send, &reply);
|
||||
if (err != NO_ERROR) return err;
|
||||
if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
|
||||
return (status_t)reply.readInt32();
|
||||
}
|
||||
|
||||
status_t BpBinder::dump(int fd, const Vector<String16>& args)
|
||||
{
|
||||
Parcel send;
|
||||
Parcel reply;
|
||||
send.writeFileDescriptor(fd);
|
||||
const size_t numArgs = args.size();
|
||||
send.writeInt32(numArgs);
|
||||
for (size_t i = 0; i < numArgs; i++) {
|
||||
send.writeString16(args[i]);
|
||||
}
|
||||
status_t err = transact(DUMP_TRANSACTION, send, &reply);
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t BpBinder::transact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
// Once a binder has died, it will never come back to life.
|
||||
if (mAlive) {
|
||||
status_t status = IPCThreadState::self()->transact(
|
||||
mHandle, code, data, reply, flags);
|
||||
if (status == DEAD_OBJECT) mAlive = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
status_t BpBinder::linkToDeath(
|
||||
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
|
||||
{
|
||||
Obituary ob;
|
||||
ob.recipient = recipient;
|
||||
ob.cookie = cookie;
|
||||
ob.flags = flags;
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(recipient == NULL,
|
||||
"linkToDeath(): recipient must be non-NULL");
|
||||
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (!mObitsSent) {
|
||||
if (!mObituaries) {
|
||||
mObituaries = new Vector<Obituary>;
|
||||
if (!mObituaries) {
|
||||
return NO_MEMORY;
|
||||
}
|
||||
LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
|
||||
getWeakRefs()->incWeak(this);
|
||||
IPCThreadState* self = IPCThreadState::self();
|
||||
self->requestDeathNotification(mHandle, this);
|
||||
self->flushCommands();
|
||||
}
|
||||
ssize_t res = mObituaries->add(ob);
|
||||
return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
|
||||
}
|
||||
}
|
||||
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
status_t BpBinder::unlinkToDeath(
|
||||
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
|
||||
wp<DeathRecipient>* outRecipient)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mObitsSent) {
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
const size_t N = mObituaries ? mObituaries->size() : 0;
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const Obituary& obit = mObituaries->itemAt(i);
|
||||
if ((obit.recipient == recipient
|
||||
|| (recipient == NULL && obit.cookie == cookie))
|
||||
&& obit.flags == flags) {
|
||||
const uint32_t allFlags = obit.flags|flags;
|
||||
if (outRecipient != NULL) {
|
||||
*outRecipient = mObituaries->itemAt(i).recipient;
|
||||
}
|
||||
mObituaries->removeAt(i);
|
||||
if (mObituaries->size() == 0) {
|
||||
LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
|
||||
IPCThreadState* self = IPCThreadState::self();
|
||||
self->clearDeathNotification(mHandle, this);
|
||||
self->flushCommands();
|
||||
delete mObituaries;
|
||||
mObituaries = NULL;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
void BpBinder::sendObituary()
|
||||
{
|
||||
LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
|
||||
this, mHandle, mObitsSent ? "true" : "false");
|
||||
|
||||
mAlive = 0;
|
||||
if (mObitsSent) return;
|
||||
|
||||
mLock.lock();
|
||||
Vector<Obituary>* obits = mObituaries;
|
||||
if(obits != NULL) {
|
||||
LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
|
||||
IPCThreadState* self = IPCThreadState::self();
|
||||
self->clearDeathNotification(mHandle, this);
|
||||
self->flushCommands();
|
||||
mObituaries = NULL;
|
||||
}
|
||||
mObitsSent = 1;
|
||||
mLock.unlock();
|
||||
|
||||
LOGV("Reporting death of proxy %p for %d recipients\n",
|
||||
this, obits ? obits->size() : 0);
|
||||
|
||||
if (obits != NULL) {
|
||||
const size_t N = obits->size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
reportOneDeath(obits->itemAt(i));
|
||||
}
|
||||
|
||||
delete obits;
|
||||
}
|
||||
}
|
||||
|
||||
void BpBinder::reportOneDeath(const Obituary& obit)
|
||||
{
|
||||
sp<DeathRecipient> recipient = obit.recipient.promote();
|
||||
LOGV("Reporting death to recipient: %p\n", recipient.get());
|
||||
if (recipient == NULL) return;
|
||||
|
||||
recipient->binderDied(this);
|
||||
}
|
||||
|
||||
|
||||
void BpBinder::attachObject(
|
||||
const void* objectID, void* object, void* cleanupCookie,
|
||||
object_cleanup_func func)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
|
||||
mObjects.attach(objectID, object, cleanupCookie, func);
|
||||
}
|
||||
|
||||
void* BpBinder::findObject(const void* objectID) const
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
return mObjects.find(objectID);
|
||||
}
|
||||
|
||||
void BpBinder::detachObject(const void* objectID)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
mObjects.detach(objectID);
|
||||
}
|
||||
|
||||
BpBinder* BpBinder::remoteBinder()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
BpBinder::~BpBinder()
|
||||
{
|
||||
LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
|
||||
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
|
||||
mLock.lock();
|
||||
Vector<Obituary>* obits = mObituaries;
|
||||
if(obits != NULL) {
|
||||
if (ipc) ipc->clearDeathNotification(mHandle, this);
|
||||
mObituaries = NULL;
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
if (obits != NULL) {
|
||||
// XXX Should we tell any remaining DeathRecipient
|
||||
// objects that the last strong ref has gone away, so they
|
||||
// are no longer linked?
|
||||
delete obits;
|
||||
}
|
||||
|
||||
if (ipc) {
|
||||
ipc->expungeHandle(mHandle, this);
|
||||
ipc->decWeakHandle(mHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void BpBinder::onFirstRef()
|
||||
{
|
||||
LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (ipc) ipc->incStrongHandle(mHandle);
|
||||
}
|
||||
|
||||
void BpBinder::onLastStrongRef(const void* id)
|
||||
{
|
||||
LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
|
||||
IF_LOGV() {
|
||||
printRefs();
|
||||
}
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
if (ipc) ipc->decStrongHandle(mHandle);
|
||||
}
|
||||
|
||||
bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
|
||||
{
|
||||
LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
279
libs/utils/BufferedTextOutput.cpp
Normal file
279
libs/utils/BufferedTextOutput.cpp
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/BufferedTextOutput.h>
|
||||
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/Debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <cutils/threads.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
struct BufferedTextOutput::BufferState : public RefBase
|
||||
{
|
||||
BufferState(int32_t _seq)
|
||||
: seq(_seq)
|
||||
, buffer(NULL)
|
||||
, bufferPos(0)
|
||||
, bufferSize(0)
|
||||
, atFront(true)
|
||||
, indent(0)
|
||||
, bundle(0) {
|
||||
}
|
||||
~BufferState() {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
status_t append(const char* txt, size_t len) {
|
||||
if ((len+bufferPos) > bufferSize) {
|
||||
void* b = realloc(buffer, ((len+bufferPos)*3)/2);
|
||||
if (!b) return NO_MEMORY;
|
||||
buffer = (char*)b;
|
||||
}
|
||||
memcpy(buffer+bufferPos, txt, len);
|
||||
bufferPos += len;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void restart() {
|
||||
bufferPos = 0;
|
||||
atFront = true;
|
||||
if (bufferSize > 256) {
|
||||
void* b = realloc(buffer, 256);
|
||||
if (b) {
|
||||
buffer = (char*)b;
|
||||
bufferSize = 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int32_t seq;
|
||||
char* buffer;
|
||||
size_t bufferPos;
|
||||
size_t bufferSize;
|
||||
bool atFront;
|
||||
int32_t indent;
|
||||
int32_t bundle;
|
||||
};
|
||||
|
||||
struct BufferedTextOutput::ThreadState
|
||||
{
|
||||
Vector<sp<BufferedTextOutput::BufferState> > states;
|
||||
};
|
||||
|
||||
static mutex_t gMutex;
|
||||
|
||||
static thread_store_t tls;
|
||||
|
||||
BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
|
||||
{
|
||||
ThreadState* ts = (ThreadState*) thread_store_get( &tls );
|
||||
if (ts) return ts;
|
||||
ts = new ThreadState;
|
||||
thread_store_set( &tls, ts, threadDestructor );
|
||||
return ts;
|
||||
}
|
||||
|
||||
void BufferedTextOutput::threadDestructor(void *st)
|
||||
{
|
||||
delete ((ThreadState*)st);
|
||||
}
|
||||
|
||||
static volatile int32_t gSequence = 0;
|
||||
|
||||
static volatile int32_t gFreeBufferIndex = -1;
|
||||
|
||||
static int32_t allocBufferIndex()
|
||||
{
|
||||
int32_t res = -1;
|
||||
|
||||
mutex_lock(&gMutex);
|
||||
|
||||
if (gFreeBufferIndex >= 0) {
|
||||
res = gFreeBufferIndex;
|
||||
gFreeBufferIndex = gTextBuffers[res];
|
||||
gTextBuffers.editItemAt(res) = -1;
|
||||
|
||||
} else {
|
||||
res = gTextBuffers.size();
|
||||
gTextBuffers.add(-1);
|
||||
}
|
||||
|
||||
mutex_unlock(&gMutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void freeBufferIndex(int32_t idx)
|
||||
{
|
||||
mutex_lock(&gMutex);
|
||||
gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
|
||||
gFreeBufferIndex = idx;
|
||||
mutex_unlock(&gMutex);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BufferedTextOutput::BufferedTextOutput(uint32_t flags)
|
||||
: mFlags(flags)
|
||||
, mSeq(android_atomic_inc(&gSequence))
|
||||
, mIndex(allocBufferIndex())
|
||||
{
|
||||
mGlobalState = new BufferState(mSeq);
|
||||
if (mGlobalState) mGlobalState->incStrong(this);
|
||||
}
|
||||
|
||||
BufferedTextOutput::~BufferedTextOutput()
|
||||
{
|
||||
if (mGlobalState) mGlobalState->decStrong(this);
|
||||
freeBufferIndex(mIndex);
|
||||
}
|
||||
|
||||
status_t BufferedTextOutput::print(const char* txt, size_t len)
|
||||
{
|
||||
//printf("BufferedTextOutput: printing %d\n", len);
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
BufferState* b = getBuffer();
|
||||
|
||||
const char* const end = txt+len;
|
||||
|
||||
status_t err;
|
||||
|
||||
while (txt < end) {
|
||||
// Find the next line.
|
||||
const char* first = txt;
|
||||
while (txt < end && *txt != '\n') txt++;
|
||||
|
||||
// Include this and all following empty lines.
|
||||
while (txt < end && *txt == '\n') txt++;
|
||||
|
||||
// Special cases for first data on a line.
|
||||
if (b->atFront) {
|
||||
if (b->indent > 0) {
|
||||
// If this is the start of a line, add the indent.
|
||||
const char* prefix = stringForIndent(b->indent);
|
||||
err = b->append(prefix, strlen(prefix));
|
||||
if (err != NO_ERROR) return err;
|
||||
|
||||
} else if (*(txt-1) == '\n' && !b->bundle) {
|
||||
// Fast path: if we are not indenting or bundling, and
|
||||
// have been given one or more complete lines, just write
|
||||
// them out without going through the buffer.
|
||||
|
||||
// Slurp up all of the lines.
|
||||
const char* lastLine = txt+1;
|
||||
while (txt < end) {
|
||||
if (*txt++ == '\n') lastLine = txt;
|
||||
}
|
||||
struct iovec vec;
|
||||
vec.iov_base = (void*)first;
|
||||
vec.iov_len = lastLine-first;
|
||||
//printf("Writing %d bytes of data!\n", vec.iov_len);
|
||||
writeLines(vec, 1);
|
||||
txt = lastLine;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Append the new text to the buffer.
|
||||
err = b->append(first, txt-first);
|
||||
if (err != NO_ERROR) return err;
|
||||
b->atFront = *(txt-1) == '\n';
|
||||
|
||||
// If we have finished a line and are not bundling, write
|
||||
// it out.
|
||||
//printf("Buffer is now %d bytes\n", b->bufferPos);
|
||||
if (b->atFront && !b->bundle) {
|
||||
struct iovec vec;
|
||||
vec.iov_base = b->buffer;
|
||||
vec.iov_len = b->bufferPos;
|
||||
//printf("Writing %d bytes of data!\n", vec.iov_len);
|
||||
writeLines(vec, 1);
|
||||
b->restart();
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void BufferedTextOutput::moveIndent(int delta)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
BufferState* b = getBuffer();
|
||||
b->indent += delta;
|
||||
if (b->indent < 0) b->indent = 0;
|
||||
}
|
||||
|
||||
void BufferedTextOutput::pushBundle()
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
BufferState* b = getBuffer();
|
||||
b->bundle++;
|
||||
}
|
||||
|
||||
void BufferedTextOutput::popBundle()
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
BufferState* b = getBuffer();
|
||||
b->bundle--;
|
||||
LOG_FATAL_IF(b->bundle < 0,
|
||||
"TextOutput::popBundle() called more times than pushBundle()");
|
||||
if (b->bundle < 0) b->bundle = 0;
|
||||
|
||||
if (b->bundle == 0) {
|
||||
// Last bundle, write out data if it is complete. If it is not
|
||||
// complete, don't write until the last line is done... this may
|
||||
// or may not be the write thing to do, but it's the easiest.
|
||||
if (b->bufferPos > 0 && b->atFront) {
|
||||
struct iovec vec;
|
||||
vec.iov_base = b->buffer;
|
||||
vec.iov_len = b->bufferPos;
|
||||
writeLines(vec, 1);
|
||||
b->restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
|
||||
{
|
||||
if ((mFlags&MULTITHREADED) != 0) {
|
||||
ThreadState* ts = getThreadState();
|
||||
if (ts) {
|
||||
while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL);
|
||||
BufferState* bs = ts->states[mIndex].get();
|
||||
if (bs != NULL && bs->seq == mSeq) return bs;
|
||||
|
||||
ts->states.editItemAt(mIndex) = new BufferState(mIndex);
|
||||
bs = ts->states[mIndex].get();
|
||||
if (bs != NULL) return bs;
|
||||
}
|
||||
}
|
||||
|
||||
return mGlobalState;
|
||||
}
|
||||
|
||||
}; // namespace android
|
335
libs/utils/CallStack.cpp
Normal file
335
libs/utils/CallStack.cpp
Normal file
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "CallStack"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if HAVE_DLADDR
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_CXXABI
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#include <unwind.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
namespace android {
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t count;
|
||||
size_t ignore;
|
||||
const void** addrs;
|
||||
} stack_crawl_state_t;
|
||||
|
||||
static
|
||||
_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg)
|
||||
{
|
||||
stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
|
||||
if (state->count) {
|
||||
void* ip = (void*)_Unwind_GetIP(context);
|
||||
if (ip) {
|
||||
if (state->ignore) {
|
||||
state->ignore--;
|
||||
} else {
|
||||
state->addrs[0] = ip;
|
||||
state->addrs++;
|
||||
state->count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
static
|
||||
int backtrace(const void** addrs, size_t ignore, size_t size)
|
||||
{
|
||||
stack_crawl_state_t state;
|
||||
state.count = size;
|
||||
state.ignore = ignore;
|
||||
state.addrs = addrs;
|
||||
_Unwind_Backtrace(trace_function, (void*)&state);
|
||||
return size - state.count;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static
|
||||
const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize)
|
||||
{
|
||||
#if HAVE_DLADDR
|
||||
Dl_info info;
|
||||
if (dladdr(addr, &info)) {
|
||||
*offset = info.dli_saddr;
|
||||
return info.dli_sname;
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
|
||||
{
|
||||
size_t out_len = 0;
|
||||
#if HAVE_CXXABI
|
||||
int status = 0;
|
||||
char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
|
||||
if (status == 0) {
|
||||
// OK
|
||||
if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
|
||||
else out_len = 0;
|
||||
free(demangled);
|
||||
} else {
|
||||
out_len = 0;
|
||||
}
|
||||
#endif
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
class MapInfo {
|
||||
struct mapinfo {
|
||||
struct mapinfo *next;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
char name[];
|
||||
};
|
||||
|
||||
const char *map_to_name(uint64_t pc, const char* def) {
|
||||
mapinfo* mi = getMapInfoList();
|
||||
while(mi) {
|
||||
if ((pc >= mi->start) && (pc < mi->end))
|
||||
return mi->name;
|
||||
mi = mi->next;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
mapinfo *parse_maps_line(char *line) {
|
||||
mapinfo *mi;
|
||||
int len = strlen(line);
|
||||
if (len < 1) return 0;
|
||||
line[--len] = 0;
|
||||
if (len < 50) return 0;
|
||||
if (line[20] != 'x') return 0;
|
||||
mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
|
||||
if (mi == 0) return 0;
|
||||
mi->start = strtoull(line, 0, 16);
|
||||
mi->end = strtoull(line + 9, 0, 16);
|
||||
mi->next = 0;
|
||||
strcpy(mi->name, line + 49);
|
||||
return mi;
|
||||
}
|
||||
|
||||
mapinfo* getMapInfoList() {
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (milist == 0) {
|
||||
char data[1024];
|
||||
FILE *fp;
|
||||
sprintf(data, "/proc/%d/maps", getpid());
|
||||
fp = fopen(data, "r");
|
||||
if (fp) {
|
||||
while(fgets(data, 1024, fp)) {
|
||||
mapinfo *mi = parse_maps_line(data);
|
||||
if(mi) {
|
||||
mi->next = milist;
|
||||
milist = mi;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
return milist;
|
||||
}
|
||||
mapinfo* milist;
|
||||
Mutex mLock;
|
||||
static MapInfo sMapInfo;
|
||||
|
||||
public:
|
||||
MapInfo()
|
||||
: milist(0) {
|
||||
}
|
||||
|
||||
~MapInfo() {
|
||||
while (milist) {
|
||||
mapinfo *next = milist->next;
|
||||
free(milist);
|
||||
milist = next;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *mapAddressToName(const void* pc, const char* def) {
|
||||
return sMapInfo.map_to_name((uint64_t)pc, def);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MapInfo MapInfo::sMapInfo;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
CallStack::CallStack()
|
||||
: mCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
CallStack::CallStack(const CallStack& rhs)
|
||||
: mCount(rhs.mCount)
|
||||
{
|
||||
if (mCount) {
|
||||
memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
|
||||
}
|
||||
}
|
||||
|
||||
CallStack::~CallStack()
|
||||
{
|
||||
}
|
||||
|
||||
CallStack& CallStack::operator = (const CallStack& rhs)
|
||||
{
|
||||
mCount = rhs.mCount;
|
||||
if (mCount) {
|
||||
memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CallStack::operator == (const CallStack& rhs) const {
|
||||
if (mCount != rhs.mCount)
|
||||
return false;
|
||||
return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0);
|
||||
}
|
||||
|
||||
bool CallStack::operator != (const CallStack& rhs) const {
|
||||
return !operator == (rhs);
|
||||
}
|
||||
|
||||
bool CallStack::operator < (const CallStack& rhs) const {
|
||||
if (mCount != rhs.mCount)
|
||||
return mCount < rhs.mCount;
|
||||
return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0;
|
||||
}
|
||||
|
||||
bool CallStack::operator >= (const CallStack& rhs) const {
|
||||
return !operator < (rhs);
|
||||
}
|
||||
|
||||
bool CallStack::operator > (const CallStack& rhs) const {
|
||||
if (mCount != rhs.mCount)
|
||||
return mCount > rhs.mCount;
|
||||
return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0;
|
||||
}
|
||||
|
||||
bool CallStack::operator <= (const CallStack& rhs) const {
|
||||
return !operator > (rhs);
|
||||
}
|
||||
|
||||
const void* CallStack::operator [] (int index) const {
|
||||
if (index >= int(mCount))
|
||||
return 0;
|
||||
return mStack[index];
|
||||
}
|
||||
|
||||
|
||||
void CallStack::clear()
|
||||
{
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
void CallStack::update(int32_t ignoreDepth, int32_t maxDepth)
|
||||
{
|
||||
if (maxDepth > MAX_DEPTH)
|
||||
maxDepth = MAX_DEPTH;
|
||||
mCount = backtrace(mStack, ignoreDepth, maxDepth);
|
||||
}
|
||||
|
||||
// Return the stack frame name on the designated level
|
||||
String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
|
||||
{
|
||||
String8 res;
|
||||
char namebuf[1024];
|
||||
char tmp[256];
|
||||
char tmp1[32];
|
||||
char tmp2[32];
|
||||
void *offs;
|
||||
|
||||
const void* ip = mStack[level];
|
||||
if (!ip) return res;
|
||||
|
||||
if (prefix) res.append(prefix);
|
||||
snprintf(tmp1, 32, "#%02d ", level);
|
||||
res.append(tmp1);
|
||||
|
||||
const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf));
|
||||
if (name) {
|
||||
if (linux_gcc_demangler(name, tmp, 256) != 0)
|
||||
name = tmp;
|
||||
snprintf(tmp1, 32, "0x%p: <", ip);
|
||||
snprintf(tmp2, 32, ">+0x%p", offs);
|
||||
res.append(tmp1);
|
||||
res.append(name);
|
||||
res.append(tmp2);
|
||||
} else {
|
||||
name = MapInfo::mapAddressToName(ip, "<unknown>");
|
||||
snprintf(tmp, 256, "pc %p %s", ip, name);
|
||||
res.append(tmp);
|
||||
}
|
||||
res.append("\n");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Dump a stack trace to the log
|
||||
void CallStack::dump(const char* prefix) const
|
||||
{
|
||||
/*
|
||||
* Sending a single long log may be truncated since the stack levels can
|
||||
* get very deep. So we request function names of each frame individually.
|
||||
*/
|
||||
for (int i=0; i<int(mCount); i++) {
|
||||
LOGD("%s", toStringSingleLevel(prefix, i).string());
|
||||
}
|
||||
}
|
||||
|
||||
// Return a string (possibly very long) containing the complete stack trace
|
||||
String8 CallStack::toString(const char* prefix) const
|
||||
{
|
||||
String8 res;
|
||||
|
||||
for (int i=0; i<int(mCount); i++) {
|
||||
res.append(toStringSingleLevel(prefix, i).string());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
}; // namespace android
|
318
libs/utils/Debug.cpp
Normal file
318
libs/utils/Debug.cpp
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/Debug.h>
|
||||
|
||||
#include <utils/misc.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static const char indentStr[] =
|
||||
" "
|
||||
" ";
|
||||
|
||||
const char* stringForIndent(int32_t indentLevel)
|
||||
{
|
||||
ssize_t off = sizeof(indentStr)-1-(indentLevel*2);
|
||||
return indentStr + (off < 0 ? 0 : off);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static void defaultPrintFunc(void* cookie, const char* txt)
|
||||
{
|
||||
printf("%s", txt);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static inline int isident(int c)
|
||||
{
|
||||
return isalnum(c) || c == '_';
|
||||
}
|
||||
|
||||
static inline bool isasciitype(char c)
|
||||
{
|
||||
if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline char makehexdigit(uint32_t val)
|
||||
{
|
||||
return "0123456789abcdef"[val&0xF];
|
||||
}
|
||||
|
||||
static char* appendhexnum(uint32_t val, char* out)
|
||||
{
|
||||
for( int32_t i=28; i>=0; i-=4 ) {
|
||||
*out++ = makehexdigit( val>>i );
|
||||
}
|
||||
*out = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline char makeupperhexdigit(uint32_t val)
|
||||
{
|
||||
return "0123456789ABCDEF"[val&0xF];
|
||||
}
|
||||
|
||||
static char* appendupperhexnum(uint32_t val, char* out)
|
||||
{
|
||||
for( int32_t i=28; i>=0; i-=4 ) {
|
||||
*out++ = makeupperhexdigit( val>>i );
|
||||
}
|
||||
*out = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char* appendcharornum(char c, char* out, bool skipzero = true)
|
||||
{
|
||||
if (skipzero && c == 0) return out;
|
||||
|
||||
if (isasciitype(c)) {
|
||||
*out++ = c;
|
||||
return out;
|
||||
}
|
||||
|
||||
*out++ = '\\';
|
||||
*out++ = 'x';
|
||||
*out++ = makehexdigit(c>>4);
|
||||
*out++ = makehexdigit(c);
|
||||
return out;
|
||||
}
|
||||
|
||||
static char* typetostring(uint32_t type, char* out,
|
||||
bool fullContext = true,
|
||||
bool strict = false)
|
||||
{
|
||||
char* pos = out;
|
||||
char c[4];
|
||||
c[0] = (char)((type>>24)&0xFF);
|
||||
c[1] = (char)((type>>16)&0xFF);
|
||||
c[2] = (char)((type>>8)&0xFF);
|
||||
c[3] = (char)(type&0xFF);
|
||||
bool valid;
|
||||
if( !strict ) {
|
||||
// now even less strict!
|
||||
// valid = isasciitype(c[3]);
|
||||
valid = true;
|
||||
int32_t i = 0;
|
||||
bool zero = true;
|
||||
while (valid && i<3) {
|
||||
if (c[i] == 0) {
|
||||
if (!zero) valid = false;
|
||||
} else {
|
||||
zero = false;
|
||||
//if (!isasciitype(c[i])) valid = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// if all zeros, not a valid type code.
|
||||
if (zero) valid = false;
|
||||
} else {
|
||||
valid = isident(c[3]) ? true : false;
|
||||
int32_t i = 0;
|
||||
bool zero = true;
|
||||
while (valid && i<3) {
|
||||
if (c[i] == 0) {
|
||||
if (!zero) valid = false;
|
||||
} else {
|
||||
zero = false;
|
||||
if (!isident(c[i])) valid = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) {
|
||||
if( fullContext ) *pos++ = '\'';
|
||||
pos = appendcharornum(c[0], pos);
|
||||
pos = appendcharornum(c[1], pos);
|
||||
pos = appendcharornum(c[2], pos);
|
||||
pos = appendcharornum(c[3], pos);
|
||||
if( fullContext ) *pos++ = '\'';
|
||||
*pos = 0;
|
||||
return pos;
|
||||
}
|
||||
|
||||
if( fullContext ) {
|
||||
*pos++ = '0';
|
||||
*pos++ = 'x';
|
||||
}
|
||||
return appendhexnum(type, pos);
|
||||
}
|
||||
|
||||
void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie)
|
||||
{
|
||||
char buffer[32];
|
||||
char* end = typetostring(typeCode, buffer);
|
||||
*end = 0;
|
||||
func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer);
|
||||
}
|
||||
|
||||
void printHexData(int32_t indent, const void *buf, size_t length,
|
||||
size_t bytesPerLine, int32_t singleLineBytesCutoff,
|
||||
size_t alignment, bool cStyle,
|
||||
debugPrintFunc func, void* cookie)
|
||||
{
|
||||
if (alignment == 0) {
|
||||
if (bytesPerLine >= 16) alignment = 4;
|
||||
else if (bytesPerLine >= 8) alignment = 2;
|
||||
else alignment = 1;
|
||||
}
|
||||
if (func == NULL) func = defaultPrintFunc;
|
||||
|
||||
size_t offset;
|
||||
|
||||
unsigned char *pos = (unsigned char *)buf;
|
||||
|
||||
if (pos == NULL) {
|
||||
if (singleLineBytesCutoff < 0) func(cookie, "\n");
|
||||
func(cookie, "(NULL)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
if (singleLineBytesCutoff < 0) func(cookie, "\n");
|
||||
func(cookie, "(empty)");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int32_t)length < 0) {
|
||||
if (singleLineBytesCutoff < 0) func(cookie, "\n");
|
||||
char buf[64];
|
||||
sprintf(buf, "(bad length: %d)", length);
|
||||
func(cookie, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[256];
|
||||
static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
|
||||
|
||||
if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
|
||||
|
||||
const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
|
||||
bool newLine = false;
|
||||
if (cStyle) {
|
||||
indent++;
|
||||
func(cookie, "{\n");
|
||||
newLine = true;
|
||||
} else if (!oneLine) {
|
||||
func(cookie, "\n");
|
||||
newLine = true;
|
||||
}
|
||||
|
||||
for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
|
||||
long remain = length;
|
||||
|
||||
char* c = buffer;
|
||||
if (!oneLine && !cStyle) {
|
||||
sprintf(c, "0x%08x: ", (int)offset);
|
||||
c += 12;
|
||||
}
|
||||
|
||||
size_t index;
|
||||
size_t word;
|
||||
|
||||
for (word = 0; word < bytesPerLine; ) {
|
||||
|
||||
#ifdef HAVE_LITTLE_ENDIAN
|
||||
const size_t startIndex = word+(alignment-(alignment?1:0));
|
||||
const ssize_t dir = -1;
|
||||
#else
|
||||
const size_t startIndex = word;
|
||||
const ssize_t dir = 1;
|
||||
#endif
|
||||
|
||||
for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
|
||||
|
||||
if (!cStyle) {
|
||||
if (index == 0 && word > 0 && alignment > 0) {
|
||||
*c++ = ' ';
|
||||
}
|
||||
|
||||
if (remain-- > 0) {
|
||||
const unsigned char val = *(pos+startIndex+(index*dir));
|
||||
*c++ = makehexdigit(val>>4);
|
||||
*c++ = makehexdigit(val);
|
||||
} else if (!oneLine) {
|
||||
*c++ = ' ';
|
||||
*c++ = ' ';
|
||||
}
|
||||
} else {
|
||||
if (remain > 0) {
|
||||
if (index == 0 && word > 0) {
|
||||
*c++ = ',';
|
||||
*c++ = ' ';
|
||||
}
|
||||
if (index == 0) {
|
||||
*c++ = '0';
|
||||
*c++ = 'x';
|
||||
}
|
||||
const unsigned char val = *(pos+startIndex+(index*dir));
|
||||
*c++ = makehexdigit(val>>4);
|
||||
*c++ = makehexdigit(val);
|
||||
remain--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
word += index;
|
||||
}
|
||||
|
||||
if (!cStyle) {
|
||||
remain = length;
|
||||
*c++ = ' ';
|
||||
*c++ = '\'';
|
||||
for (index = 0; index < bytesPerLine; index++) {
|
||||
|
||||
if (remain-- > 0) {
|
||||
const unsigned char val = pos[index];
|
||||
*c++ = (val >= ' ' && val < 127) ? val : '.';
|
||||
} else if (!oneLine) {
|
||||
*c++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
*c++ = '\'';
|
||||
if (length > bytesPerLine) *c++ = '\n';
|
||||
} else {
|
||||
if (remain > 0) *c++ = ',';
|
||||
*c++ = '\n';
|
||||
}
|
||||
|
||||
if (newLine && indent) func(cookie, stringForIndent(indent));
|
||||
*c = 0;
|
||||
func(cookie, buffer);
|
||||
newLine = true;
|
||||
|
||||
if (length <= bytesPerLine) break;
|
||||
length -= bytesPerLine;
|
||||
}
|
||||
|
||||
if (cStyle) {
|
||||
if (indent > 0) func(cookie, stringForIndent(indent-1));
|
||||
func(cookie, "};");
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
222
libs/utils/FileMap.cpp
Normal file
222
libs/utils/FileMap.cpp
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Shared file mapping class.
|
||||
//
|
||||
|
||||
#define LOG_TAG "filemap"
|
||||
|
||||
#include <utils/FileMap.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_POSIX_FILEMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
/*static*/ long FileMap::mPageSize = -1;
|
||||
|
||||
|
||||
/*
|
||||
* Constructor. Create an empty object.
|
||||
*/
|
||||
FileMap::FileMap(void)
|
||||
: mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
|
||||
mDataPtr(NULL), mDataLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor.
|
||||
*/
|
||||
FileMap::~FileMap(void)
|
||||
{
|
||||
assert(mRefCount == 0);
|
||||
|
||||
//printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
|
||||
|
||||
mRefCount = -100; // help catch double-free
|
||||
if (mFileName != NULL) {
|
||||
free(mFileName);
|
||||
}
|
||||
#ifdef HAVE_POSIX_FILEMAP
|
||||
if (munmap(mBasePtr, mBaseLength) != 0) {
|
||||
LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_WIN32_FILEMAP
|
||||
if ( UnmapViewOfFile(mBasePtr) == 0) {
|
||||
LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
|
||||
GetLastError() );
|
||||
}
|
||||
CloseHandle(mFileMapping);
|
||||
CloseHandle(mFileHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 FileMap::create(const char* origFileName, int fd, off_t offset, size_t length, bool readOnly)
|
||||
{
|
||||
#ifdef HAVE_WIN32_FILEMAP
|
||||
int adjust;
|
||||
off_t adjOffset;
|
||||
size_t adjLength;
|
||||
|
||||
if (mPageSize == -1) {
|
||||
SYSTEM_INFO si;
|
||||
|
||||
GetSystemInfo( &si );
|
||||
mPageSize = si.dwAllocationGranularity;
|
||||
}
|
||||
|
||||
DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
|
||||
|
||||
mFileHandle = (HANDLE) _get_osfhandle(fd);
|
||||
mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
|
||||
if (mFileMapping == NULL) {
|
||||
LOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
|
||||
mFileHandle, protect, GetLastError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
adjust = offset % mPageSize;
|
||||
adjOffset = offset - adjust;
|
||||
adjLength = length + adjust;
|
||||
|
||||
mBasePtr = MapViewOfFile( mFileMapping,
|
||||
readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
|
||||
0,
|
||||
(DWORD)(adjOffset),
|
||||
adjLength );
|
||||
if (mBasePtr == NULL) {
|
||||
LOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
|
||||
adjOffset, adjLength, GetLastError() );
|
||||
CloseHandle(mFileMapping);
|
||||
mFileMapping = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_POSIX_FILEMAP
|
||||
int prot, flags, adjust;
|
||||
off_t adjOffset;
|
||||
size_t adjLength;
|
||||
|
||||
void* ptr;
|
||||
|
||||
assert(mRefCount == 1);
|
||||
assert(fd >= 0);
|
||||
assert(offset >= 0);
|
||||
assert(length > 0);
|
||||
|
||||
/* init on first use */
|
||||
if (mPageSize == -1) {
|
||||
#if NOT_USING_KLIBC
|
||||
mPageSize = sysconf(_SC_PAGESIZE);
|
||||
if (mPageSize == -1) {
|
||||
LOGE("could not get _SC_PAGESIZE\n");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
/* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
|
||||
mPageSize = 4096;
|
||||
#endif
|
||||
}
|
||||
|
||||
adjust = offset % mPageSize;
|
||||
try_again:
|
||||
adjOffset = offset - adjust;
|
||||
adjLength = length + adjust;
|
||||
|
||||
flags = MAP_SHARED;
|
||||
prot = PROT_READ;
|
||||
if (!readOnly)
|
||||
prot |= PROT_WRITE;
|
||||
|
||||
ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
|
||||
if (ptr == MAP_FAILED) {
|
||||
// Cygwin does not seem to like file mapping files from an offset.
|
||||
// So if we fail, try again with offset zero
|
||||
if (adjOffset > 0) {
|
||||
adjust = offset;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
LOGE("mmap(%ld,%ld) failed: %s\n",
|
||||
(long) adjOffset, (long) adjLength, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
mBasePtr = ptr;
|
||||
#endif /* HAVE_POSIX_FILEMAP */
|
||||
|
||||
mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
|
||||
mBaseLength = adjLength;
|
||||
mDataOffset = offset;
|
||||
mDataPtr = (char*) mBasePtr + adjust;
|
||||
mDataLength = length;
|
||||
|
||||
assert(mBasePtr != NULL);
|
||||
|
||||
LOGV("MAP: base %p/%d data %p/%d\n",
|
||||
mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide guidance to the system.
|
||||
*/
|
||||
int FileMap::advise(MapAdvice advice)
|
||||
{
|
||||
#if HAVE_MADVISE
|
||||
int cc, sysAdvice;
|
||||
|
||||
switch (advice) {
|
||||
case NORMAL: sysAdvice = MADV_NORMAL; break;
|
||||
case RANDOM: sysAdvice = MADV_RANDOM; break;
|
||||
case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break;
|
||||
case WILLNEED: sysAdvice = MADV_WILLNEED; break;
|
||||
case DONTNEED: sysAdvice = MADV_DONTNEED; break;
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cc = madvise(mBasePtr, mBaseLength, sysAdvice);
|
||||
if (cc != 0)
|
||||
LOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
|
||||
return cc;
|
||||
#else
|
||||
return -1;
|
||||
#endif // HAVE_MADVISE
|
||||
}
|
89
libs/utils/IDataConnection.cpp
Normal file
89
libs/utils/IDataConnection.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Parcel.h>
|
||||
|
||||
#include <utils/IDataConnection.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
enum
|
||||
{
|
||||
CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
|
||||
DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
|
||||
};
|
||||
|
||||
class BpDataConnection : public BpInterface<IDataConnection>
|
||||
{
|
||||
public:
|
||||
BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
|
||||
: BpInterface<IDataConnection>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void connect()
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IDataConnection::descriptor());
|
||||
remote()->transact(CONNECT_TRANSACTION, data, &reply);
|
||||
}
|
||||
|
||||
virtual void disconnect()
|
||||
{
|
||||
Parcel data, reply;
|
||||
remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
case CONNECT_TRANSACTION:
|
||||
{
|
||||
CHECK_INTERFACE(IDataConnection, data, reply);
|
||||
connect();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
case DISCONNECT_TRANSACTION:
|
||||
{
|
||||
CHECK_INTERFACE(IDataConnection, data, reply);
|
||||
disconnect();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
35
libs/utils/IInterface.cpp
Normal file
35
libs/utils/IInterface.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/IInterface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sp<IBinder> IInterface::asBinder()
|
||||
{
|
||||
return this ? onAsBinder() : NULL;
|
||||
}
|
||||
|
||||
sp<const IBinder> IInterface::asBinder() const
|
||||
{
|
||||
return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
486
libs/utils/IMemory.cpp
Normal file
486
libs/utils/IMemory.cpp
Normal file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "IMemory"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <utils/IMemory.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/CallStack.h>
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
namespace android {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class HeapCache : public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
HeapCache();
|
||||
virtual ~HeapCache();
|
||||
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
|
||||
void pin_heap(const sp<IBinder>& binder);
|
||||
void free_heap(const sp<IBinder>& binder);
|
||||
sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
|
||||
void dump_heaps();
|
||||
|
||||
private:
|
||||
// For IMemory.cpp
|
||||
struct heap_info_t {
|
||||
sp<IMemoryHeap> heap;
|
||||
int32_t count;
|
||||
};
|
||||
|
||||
void free_heap(const wp<IBinder>& binder);
|
||||
|
||||
Mutex mHeapCacheLock;
|
||||
KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
|
||||
};
|
||||
|
||||
static sp<HeapCache> gHeapCache = new HeapCache();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
enum {
|
||||
HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
class BpMemoryHeap : public BpInterface<IMemoryHeap>
|
||||
{
|
||||
public:
|
||||
BpMemoryHeap(const sp<IBinder>& impl);
|
||||
virtual ~BpMemoryHeap();
|
||||
|
||||
virtual int getHeapID() const;
|
||||
virtual void* getBase() const;
|
||||
virtual size_t getSize() const;
|
||||
virtual uint32_t getFlags() const;
|
||||
|
||||
private:
|
||||
friend class IMemory;
|
||||
friend class HeapCache;
|
||||
|
||||
// for debugging in this module
|
||||
static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
|
||||
return gHeapCache->find_heap(binder);
|
||||
}
|
||||
static inline void free_heap(const sp<IBinder>& binder) {
|
||||
gHeapCache->free_heap(binder);
|
||||
}
|
||||
static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
|
||||
return gHeapCache->get_heap(binder);
|
||||
}
|
||||
static inline void dump_heaps() {
|
||||
gHeapCache->dump_heaps();
|
||||
}
|
||||
void inline pin_heap() const {
|
||||
gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
|
||||
}
|
||||
|
||||
void assertMapped() const;
|
||||
void assertReallyMapped() const;
|
||||
void pinHeap() const;
|
||||
|
||||
mutable volatile int32_t mHeapId;
|
||||
mutable void* mBase;
|
||||
mutable size_t mSize;
|
||||
mutable uint32_t mFlags;
|
||||
mutable bool mRealHeap;
|
||||
mutable Mutex mLock;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
enum {
|
||||
GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
class BpMemory : public BpInterface<IMemory>
|
||||
{
|
||||
public:
|
||||
BpMemory(const sp<IBinder>& impl);
|
||||
virtual ~BpMemory();
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
|
||||
|
||||
private:
|
||||
mutable sp<IMemoryHeap> mHeap;
|
||||
mutable ssize_t mOffset;
|
||||
mutable size_t mSize;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
|
||||
{
|
||||
sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
|
||||
void* const base = realHeap->base();
|
||||
if (base == MAP_FAILED)
|
||||
return 0;
|
||||
return static_cast<char*>(base) + offset;
|
||||
}
|
||||
|
||||
void* IMemory::pointer() const {
|
||||
ssize_t offset;
|
||||
sp<IMemoryHeap> heap = getMemory(&offset);
|
||||
void* const base = heap!=0 ? heap->base() : MAP_FAILED;
|
||||
if (base == MAP_FAILED)
|
||||
return 0;
|
||||
return static_cast<char*>(base) + offset;
|
||||
}
|
||||
|
||||
size_t IMemory::size() const {
|
||||
size_t size;
|
||||
getMemory(NULL, &size);
|
||||
return size;
|
||||
}
|
||||
|
||||
ssize_t IMemory::offset() const {
|
||||
ssize_t offset;
|
||||
getMemory(&offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
BpMemory::BpMemory(const sp<IBinder>& impl)
|
||||
: BpInterface<IMemory>(impl), mOffset(0), mSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
BpMemory::~BpMemory()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
|
||||
{
|
||||
if (mHeap == 0) {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
|
||||
if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
|
||||
sp<IBinder> heap = reply.readStrongBinder();
|
||||
ssize_t o = reply.readInt32();
|
||||
size_t s = reply.readInt32();
|
||||
if (heap != 0) {
|
||||
mHeap = interface_cast<IMemoryHeap>(heap);
|
||||
if (mHeap != 0) {
|
||||
mOffset = o;
|
||||
mSize = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset) *offset = mOffset;
|
||||
if (size) *size = mSize;
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnMemory::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
case GET_MEMORY: {
|
||||
CHECK_INTERFACE(IMemory, data, reply);
|
||||
ssize_t offset;
|
||||
size_t size;
|
||||
reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
|
||||
reply->writeInt32(offset);
|
||||
reply->writeInt32(size);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
|
||||
: BpInterface<IMemoryHeap>(impl),
|
||||
mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
|
||||
{
|
||||
}
|
||||
|
||||
BpMemoryHeap::~BpMemoryHeap() {
|
||||
if (mHeapId != -1) {
|
||||
close(mHeapId);
|
||||
if (mRealHeap) {
|
||||
// by construction we're the last one
|
||||
if (mBase != MAP_FAILED) {
|
||||
sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
|
||||
|
||||
if (VERBOSE) {
|
||||
LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
|
||||
binder.get(), this, mSize, mHeapId);
|
||||
CallStack stack;
|
||||
stack.update();
|
||||
stack.dump("callstack");
|
||||
}
|
||||
|
||||
munmap(mBase, mSize);
|
||||
}
|
||||
} else {
|
||||
// remove from list only if it was mapped before
|
||||
sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
|
||||
free_heap(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BpMemoryHeap::assertMapped() const
|
||||
{
|
||||
if (mHeapId == -1) {
|
||||
sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
|
||||
sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
|
||||
heap->assertReallyMapped();
|
||||
if (heap->mBase != MAP_FAILED) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (mHeapId == -1) {
|
||||
mBase = heap->mBase;
|
||||
mSize = heap->mSize;
|
||||
android_atomic_write( dup( heap->mHeapId ), &mHeapId );
|
||||
}
|
||||
} else {
|
||||
// something went wrong
|
||||
free_heap(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BpMemoryHeap::assertReallyMapped() const
|
||||
{
|
||||
if (mHeapId == -1) {
|
||||
|
||||
// remote call without mLock held, worse case scenario, we end up
|
||||
// calling transact() from multiple threads, but that's not a problem,
|
||||
// only mmap below must be in the critical section.
|
||||
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
|
||||
status_t err = remote()->transact(HEAP_ID, data, &reply);
|
||||
int parcel_fd = reply.readFileDescriptor();
|
||||
ssize_t size = reply.readInt32();
|
||||
uint32_t flags = reply.readInt32();
|
||||
|
||||
LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
|
||||
asBinder().get(), parcel_fd, size, err, strerror(-err));
|
||||
|
||||
int fd = dup( parcel_fd );
|
||||
LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
|
||||
parcel_fd, size, err, strerror(errno));
|
||||
|
||||
int access = PROT_READ;
|
||||
if (!(flags & READ_ONLY)) {
|
||||
access |= PROT_WRITE;
|
||||
}
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (mHeapId == -1) {
|
||||
mRealHeap = true;
|
||||
mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
|
||||
if (mBase == MAP_FAILED) {
|
||||
LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
|
||||
asBinder().get(), size, fd, strerror(errno));
|
||||
close(fd);
|
||||
} else {
|
||||
if (flags & MAP_ONCE) {
|
||||
//LOGD("pinning heap (binder=%p, size=%d, fd=%d",
|
||||
// asBinder().get(), size, fd);
|
||||
pin_heap();
|
||||
}
|
||||
mSize = size;
|
||||
mFlags = flags;
|
||||
android_atomic_write(fd, &mHeapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BpMemoryHeap::getHeapID() const {
|
||||
assertMapped();
|
||||
return mHeapId;
|
||||
}
|
||||
|
||||
void* BpMemoryHeap::getBase() const {
|
||||
assertMapped();
|
||||
return mBase;
|
||||
}
|
||||
|
||||
size_t BpMemoryHeap::getSize() const {
|
||||
assertMapped();
|
||||
return mSize;
|
||||
}
|
||||
|
||||
uint32_t BpMemoryHeap::getFlags() const {
|
||||
assertMapped();
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
|
||||
|
||||
status_t BnMemoryHeap::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
case HEAP_ID: {
|
||||
CHECK_INTERFACE(IMemoryHeap, data, reply);
|
||||
reply->writeFileDescriptor(getHeapID());
|
||||
reply->writeInt32(getSize());
|
||||
reply->writeInt32(getFlags());
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
HeapCache::HeapCache()
|
||||
: DeathRecipient()
|
||||
{
|
||||
}
|
||||
|
||||
HeapCache::~HeapCache()
|
||||
{
|
||||
}
|
||||
|
||||
void HeapCache::binderDied(const wp<IBinder>& binder)
|
||||
{
|
||||
//LOGD("binderDied binder=%p", binder.unsafe_get());
|
||||
free_heap(binder);
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) {
|
||||
heap_info_t& info = mHeapCache.editValueAt(i);
|
||||
LOGD_IF(VERBOSE,
|
||||
"found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
|
||||
binder.get(), info.heap.get(),
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
|
||||
info.count);
|
||||
android_atomic_inc(&info.count);
|
||||
return info.heap;
|
||||
} else {
|
||||
heap_info_t info;
|
||||
info.heap = interface_cast<IMemoryHeap>(binder);
|
||||
info.count = 1;
|
||||
//LOGD("adding binder=%p, heap=%p, count=%d",
|
||||
// binder.get(), info.heap.get(), info.count);
|
||||
mHeapCache.add(binder, info);
|
||||
return info.heap;
|
||||
}
|
||||
}
|
||||
|
||||
void HeapCache::pin_heap(const sp<IBinder>& binder)
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) {
|
||||
heap_info_t& info(mHeapCache.editValueAt(i));
|
||||
android_atomic_inc(&info.count);
|
||||
binder->linkToDeath(this);
|
||||
} else {
|
||||
LOGE("pin_heap binder=%p not found!!!", binder.get());
|
||||
}
|
||||
}
|
||||
|
||||
void HeapCache::free_heap(const sp<IBinder>& binder) {
|
||||
free_heap( wp<IBinder>(binder) );
|
||||
}
|
||||
|
||||
void HeapCache::free_heap(const wp<IBinder>& binder)
|
||||
{
|
||||
sp<IMemoryHeap> rel;
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) {
|
||||
heap_info_t& info(mHeapCache.editValueAt(i));
|
||||
int32_t c = android_atomic_dec(&info.count);
|
||||
if (c == 1) {
|
||||
LOGD_IF(VERBOSE,
|
||||
"removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
|
||||
binder.unsafe_get(), info.heap.get(),
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
|
||||
static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
|
||||
info.count);
|
||||
rel = mHeapCache.valueAt(i).heap;
|
||||
mHeapCache.removeItemsAt(i);
|
||||
}
|
||||
} else {
|
||||
LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
|
||||
{
|
||||
sp<IMemoryHeap> realHeap;
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
ssize_t i = mHeapCache.indexOfKey(binder);
|
||||
if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
|
||||
else realHeap = interface_cast<IMemoryHeap>(binder);
|
||||
return realHeap;
|
||||
}
|
||||
|
||||
void HeapCache::dump_heaps()
|
||||
{
|
||||
Mutex::Autolock _l(mHeapCacheLock);
|
||||
int c = mHeapCache.size();
|
||||
for (int i=0 ; i<c ; i++) {
|
||||
const heap_info_t& info = mHeapCache.valueAt(i);
|
||||
BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
|
||||
LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
|
||||
mHeapCache.keyAt(i).unsafe_get(),
|
||||
info.heap.get(), info.count,
|
||||
h->mHeapId, h->mBase, h->mSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
1030
libs/utils/IPCThreadState.cpp
Normal file
1030
libs/utils/IPCThreadState.cpp
Normal file
File diff suppressed because it is too large
Load diff
86
libs/utils/IPermissionController.cpp
Normal file
86
libs/utils/IPermissionController.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "PermissionController"
|
||||
|
||||
#include <utils/IPermissionController.h>
|
||||
|
||||
#include <utils/Debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class BpPermissionController : public BpInterface<IPermissionController>
|
||||
{
|
||||
public:
|
||||
BpPermissionController(const sp<IBinder>& impl)
|
||||
: BpInterface<IPermissionController>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
|
||||
data.writeString16(permission);
|
||||
data.writeInt32(pid);
|
||||
data.writeInt32(uid);
|
||||
remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
|
||||
// fail on exception
|
||||
if (reply.readInt32() != 0) return 0;
|
||||
return reply.readInt32() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnPermissionController::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
//printf("PermissionController received: "); data.print();
|
||||
switch(code) {
|
||||
case CHECK_PERMISSION_TRANSACTION: {
|
||||
CHECK_INTERFACE(IPermissionController, data, reply);
|
||||
String16 permission = data.readString16();
|
||||
int32_t pid = data.readInt32();
|
||||
int32_t uid = data.readInt32();
|
||||
bool res = checkPermission(permission, pid, uid);
|
||||
// write exception
|
||||
reply->writeInt32(0);
|
||||
reply->writeInt32(res ? 1 : 0);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
230
libs/utils/IServiceManager.cpp
Normal file
230
libs/utils/IServiceManager.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "ServiceManager"
|
||||
|
||||
#include <utils/IServiceManager.h>
|
||||
|
||||
#include <utils/Debug.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Parcel.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
sp<IServiceManager> defaultServiceManager()
|
||||
{
|
||||
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
|
||||
|
||||
{
|
||||
AutoMutex _l(gDefaultServiceManagerLock);
|
||||
if (gDefaultServiceManager == NULL) {
|
||||
gDefaultServiceManager = interface_cast<IServiceManager>(
|
||||
ProcessState::self()->getContextObject(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
return gDefaultServiceManager;
|
||||
}
|
||||
|
||||
bool checkCallingPermission(const String16& permission)
|
||||
{
|
||||
return checkCallingPermission(permission, NULL, NULL);
|
||||
}
|
||||
|
||||
static String16 _permission("permission");
|
||||
|
||||
bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
|
||||
{
|
||||
IPCThreadState* ipcState = IPCThreadState::self();
|
||||
int32_t pid = ipcState->getCallingPid();
|
||||
int32_t uid = ipcState->getCallingUid();
|
||||
if (outPid) *outPid = pid;
|
||||
if (outUid) *outUid= uid;
|
||||
|
||||
sp<IPermissionController> pc;
|
||||
gDefaultServiceManagerLock.lock();
|
||||
pc = gPermissionController;
|
||||
gDefaultServiceManagerLock.unlock();
|
||||
|
||||
int64_t startTime = 0;
|
||||
|
||||
while (true) {
|
||||
if (pc != NULL) {
|
||||
bool res = pc->checkPermission(permission, pid, uid);
|
||||
if (res) {
|
||||
if (startTime != 0) {
|
||||
LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
|
||||
(int)((uptimeMillis()-startTime)/1000),
|
||||
String8(permission).string(), uid, pid);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Is this a permission failure, or did the controller go away?
|
||||
if (pc->asBinder()->isBinderAlive()) {
|
||||
LOGW("Permission failure: %s from uid=%d pid=%d",
|
||||
String8(permission).string(), uid, pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Object is dead!
|
||||
gDefaultServiceManagerLock.lock();
|
||||
if (gPermissionController == pc) {
|
||||
gPermissionController = NULL;
|
||||
}
|
||||
gDefaultServiceManagerLock.unlock();
|
||||
}
|
||||
|
||||
// Need to retrieve the permission controller.
|
||||
sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
|
||||
if (binder == NULL) {
|
||||
// Wait for the permission controller to come back...
|
||||
if (startTime == 0) {
|
||||
startTime = uptimeMillis();
|
||||
LOGI("Waiting to check permission %s from uid=%d pid=%d",
|
||||
String8(permission).string(), uid, pid);
|
||||
}
|
||||
sleep(1);
|
||||
} else {
|
||||
pc = interface_cast<IPermissionController>(binder);
|
||||
// Install the new permission controller, and try again.
|
||||
gDefaultServiceManagerLock.lock();
|
||||
gPermissionController = pc;
|
||||
gDefaultServiceManagerLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class BpServiceManager : public BpInterface<IServiceManager>
|
||||
{
|
||||
public:
|
||||
BpServiceManager(const sp<IBinder>& impl)
|
||||
: BpInterface<IServiceManager>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual sp<IBinder> getService(const String16& name) const
|
||||
{
|
||||
unsigned n;
|
||||
for (n = 0; n < 5; n++){
|
||||
sp<IBinder> svc = checkService(name);
|
||||
if (svc != NULL) return svc;
|
||||
LOGI("Waiting for sevice %s...\n", String8(name).string());
|
||||
sleep(1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual sp<IBinder> checkService( const String16& name) const
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
|
||||
data.writeString16(name);
|
||||
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
|
||||
return reply.readStrongBinder();
|
||||
}
|
||||
|
||||
virtual status_t addService(const String16& name, const sp<IBinder>& service)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
|
||||
data.writeString16(name);
|
||||
data.writeStrongBinder(service);
|
||||
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
|
||||
return err == NO_ERROR ? reply.readInt32() : err;
|
||||
}
|
||||
|
||||
virtual Vector<String16> listServices()
|
||||
{
|
||||
Vector<String16> res;
|
||||
int n = 0;
|
||||
|
||||
for (;;) {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
|
||||
data.writeInt32(n++);
|
||||
status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
|
||||
if (err != NO_ERROR)
|
||||
break;
|
||||
res.add(reply.readString16());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#define CHECK_INTERFACE(interface, data, reply) \
|
||||
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
|
||||
LOGW("Call incorrectly routed to " #interface); \
|
||||
return PERMISSION_DENIED; \
|
||||
} } while (0)
|
||||
|
||||
status_t BnServiceManager::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
//printf("ServiceManager received: "); data.print();
|
||||
switch(code) {
|
||||
case GET_SERVICE_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
String16 which = data.readString16();
|
||||
sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
|
||||
reply->writeStrongBinder(b);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case CHECK_SERVICE_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
String16 which = data.readString16();
|
||||
sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
|
||||
reply->writeStrongBinder(b);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case ADD_SERVICE_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
String16 which = data.readString16();
|
||||
sp<IBinder> b = data.readStrongBinder();
|
||||
status_t err = addService(which, b);
|
||||
reply->writeInt32(err);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case LIST_SERVICES_TRANSACTION: {
|
||||
CHECK_INTERFACE(IServiceManager, data, reply);
|
||||
Vector<String16> list = listServices();
|
||||
const size_t N = list.size();
|
||||
reply->writeInt32(N);
|
||||
for (size_t i=0; i<N; i++) {
|
||||
reply->writeString16(list[i]);
|
||||
}
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
236
libs/utils/InetAddress.cpp
Normal file
236
libs/utils/InetAddress.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Internet address class.
|
||||
//
|
||||
#ifdef HAVE_WINSOCK
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
//# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <utils/inet_address.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* InetAddress
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
// lock for the next couple of functions; could tuck into InetAddress
|
||||
static Mutex* gGHBNLock;
|
||||
|
||||
/*
|
||||
* Lock/unlock access to the hostent struct returned by gethostbyname().
|
||||
*/
|
||||
static inline void lock_gethostbyname(void)
|
||||
{
|
||||
if (gGHBNLock == NULL)
|
||||
gGHBNLock = new Mutex;
|
||||
gGHBNLock->lock();
|
||||
}
|
||||
static inline void unlock_gethostbyname(void)
|
||||
{
|
||||
assert(gGHBNLock != NULL);
|
||||
gGHBNLock->unlock();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Constructor -- just init members. This is private so that callers
|
||||
* are required to use getByName().
|
||||
*/
|
||||
InetAddress::InetAddress(void)
|
||||
: mAddress(NULL), mLength(-1), mName(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor -- free address storage.
|
||||
*/
|
||||
InetAddress::~InetAddress(void)
|
||||
{
|
||||
delete[] (char*) mAddress;
|
||||
delete[] mName;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy constructor.
|
||||
*/
|
||||
InetAddress::InetAddress(const InetAddress& orig)
|
||||
{
|
||||
*this = orig; // use assignment code
|
||||
}
|
||||
|
||||
/*
|
||||
* Assignment operator.
|
||||
*/
|
||||
InetAddress& InetAddress::operator=(const InetAddress& addr)
|
||||
{
|
||||
// handle self-assignment
|
||||
if (this == &addr)
|
||||
return *this;
|
||||
// copy mLength and mAddress
|
||||
mLength = addr.mLength;
|
||||
if (mLength > 0) {
|
||||
mAddress = new char[mLength];
|
||||
memcpy(mAddress, addr.mAddress, mLength);
|
||||
LOG(LOG_DEBUG, "socket",
|
||||
"HEY: copied %d bytes in assignment operator\n", mLength);
|
||||
} else {
|
||||
mAddress = NULL;
|
||||
}
|
||||
// copy mName
|
||||
mName = new char[strlen(addr.mName)+1];
|
||||
strcpy(mName, addr.mName);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new object from a name or a dotted-number IP notation.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
InetAddress*
|
||||
InetAddress::getByName(const char* host)
|
||||
{
|
||||
InetAddress* newAddr = NULL;
|
||||
struct sockaddr_in addr;
|
||||
struct hostent* he;
|
||||
DurationTimer hostTimer, lockTimer;
|
||||
|
||||
// gethostbyname() isn't reentrant, so we need to lock things until
|
||||
// we can copy the data out.
|
||||
lockTimer.start();
|
||||
lock_gethostbyname();
|
||||
hostTimer.start();
|
||||
|
||||
he = gethostbyname(host);
|
||||
if (he == NULL) {
|
||||
LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
|
||||
unlock_gethostbyname();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&addr.sin_addr, he->h_addr, he->h_length);
|
||||
addr.sin_family = he->h_addrtype;
|
||||
addr.sin_port = 0;
|
||||
|
||||
// got it, unlock us
|
||||
hostTimer.stop();
|
||||
he = NULL;
|
||||
unlock_gethostbyname();
|
||||
|
||||
lockTimer.stop();
|
||||
if ((long) lockTimer.durationUsecs() > 100000) {
|
||||
long lockTime = (long) lockTimer.durationUsecs();
|
||||
long hostTime = (long) hostTimer.durationUsecs();
|
||||
LOG(LOG_DEBUG, "socket",
|
||||
"Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
|
||||
host, lockTime / 1000000.0, hostTime / 1000000.0,
|
||||
(lockTime - hostTime) / 1000000.0);
|
||||
}
|
||||
|
||||
// Alloc storage and copy it over.
|
||||
newAddr = new InetAddress();
|
||||
if (newAddr == NULL)
|
||||
return NULL;
|
||||
|
||||
newAddr->mLength = sizeof(struct sockaddr_in);
|
||||
newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
|
||||
if (newAddr->mAddress == NULL) {
|
||||
delete newAddr;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(newAddr->mAddress, &addr, newAddr->mLength);
|
||||
|
||||
// Keep this for debug messages.
|
||||
newAddr->mName = new char[strlen(host)+1];
|
||||
if (newAddr->mName == NULL) {
|
||||
delete newAddr;
|
||||
return NULL;
|
||||
}
|
||||
strcpy(newAddr->mName, host);
|
||||
|
||||
return newAddr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* InetSocketAddress
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create an address with the host wildcard (INADDR_ANY).
|
||||
*/
|
||||
bool InetSocketAddress::create(int port)
|
||||
{
|
||||
assert(mAddress == NULL);
|
||||
|
||||
mAddress = InetAddress::getByName("0.0.0.0");
|
||||
if (mAddress == NULL)
|
||||
return false;
|
||||
mPort = port;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create address with host and port specified.
|
||||
*/
|
||||
bool InetSocketAddress::create(const InetAddress* addr, int port)
|
||||
{
|
||||
assert(mAddress == NULL);
|
||||
|
||||
mAddress = new InetAddress(*addr); // make a copy
|
||||
if (mAddress == NULL)
|
||||
return false;
|
||||
mPort = port;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create address with host and port specified.
|
||||
*/
|
||||
bool InetSocketAddress::create(const char* host, int port)
|
||||
{
|
||||
assert(mAddress == NULL);
|
||||
|
||||
mAddress = InetAddress::getByName(host);
|
||||
if (mAddress == NULL)
|
||||
return false;
|
||||
mPort = port;
|
||||
return true;
|
||||
}
|
||||
|
129
libs/utils/LogSocket.cpp
Normal file
129
libs/utils/LogSocket.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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 HAVE_WINSOCK
|
||||
//#define SOCKETLOG
|
||||
#endif
|
||||
|
||||
#ifdef SOCKETLOG
|
||||
|
||||
#define LOG_TAG "SOCKETLOG"
|
||||
|
||||
#include <string.h>
|
||||
#include <cutils/log.h>
|
||||
#include "utils/LogSocket.h"
|
||||
#include "utils/logger.h"
|
||||
#include "cutils/hashmap.h"
|
||||
|
||||
// defined in //device/data/etc/event-log-tags
|
||||
#define SOCKET_CLOSE_LOG 51000
|
||||
|
||||
static Hashmap* statsMap = NULL;
|
||||
|
||||
#define LOG_LIST_NUMBER 5
|
||||
|
||||
typedef struct SocketStats {
|
||||
int fd;
|
||||
unsigned int send;
|
||||
unsigned int recv;
|
||||
unsigned int ip;
|
||||
unsigned short port;
|
||||
short reason;
|
||||
}SocketStats;
|
||||
|
||||
SocketStats *get_socket_stats(int fd) {
|
||||
if (statsMap == NULL) {
|
||||
statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals);
|
||||
}
|
||||
|
||||
SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
|
||||
if (s == NULL) {
|
||||
// LOGD("create SocketStats for fd %d", fd);
|
||||
s = (SocketStats*) malloc(sizeof(SocketStats));
|
||||
memset(s, 0, sizeof(SocketStats));
|
||||
s->fd = fd;
|
||||
hashmapPut(statsMap, &s->fd, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void log_socket_connect(int fd, unsigned int ip, unsigned short port) {
|
||||
// LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port);
|
||||
SocketStats *s = get_socket_stats(fd);
|
||||
s->ip = ip;
|
||||
s->port = port;
|
||||
}
|
||||
|
||||
void add_send_stats(int fd, int send) {
|
||||
if (send <=0) {
|
||||
LOGE("add_send_stats send %d", send);
|
||||
return;
|
||||
}
|
||||
SocketStats *s = get_socket_stats(fd);
|
||||
s->send += send;
|
||||
// LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port);
|
||||
}
|
||||
|
||||
void add_recv_stats(int fd, int recv) {
|
||||
if (recv <=0) {
|
||||
LOGE("add_recv_stats recv %d", recv);
|
||||
return;
|
||||
}
|
||||
SocketStats *s = get_socket_stats(fd);
|
||||
s->recv += recv;
|
||||
// LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port);
|
||||
}
|
||||
|
||||
char* put_int(char* buf, int value) {
|
||||
*buf = EVENT_TYPE_INT;
|
||||
buf++;
|
||||
memcpy(buf, &value, sizeof(int));
|
||||
return buf + sizeof(int);
|
||||
}
|
||||
|
||||
void log_socket_close(int fd, short reason) {
|
||||
if (statsMap) {
|
||||
SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
|
||||
if (s != NULL) {
|
||||
if (s->send != 0 || s->recv != 0) {
|
||||
s->reason = reason;
|
||||
// 5 int + list type need 2 bytes
|
||||
char buf[LOG_LIST_NUMBER * 5 + 2];
|
||||
buf[0] = EVENT_TYPE_LIST;
|
||||
buf[1] = LOG_LIST_NUMBER;
|
||||
char* writePos = buf + 2;
|
||||
writePos = put_int(writePos, s->send);
|
||||
writePos = put_int(writePos, s->recv);
|
||||
writePos = put_int(writePos, s->ip);
|
||||
writePos = put_int(writePos, s->port);
|
||||
writePos = put_int(writePos, s->reason);
|
||||
|
||||
android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf));
|
||||
// LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason);
|
||||
}
|
||||
hashmapRemove(statsMap, &s->fd);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void add_send_stats(int fd, int send) {}
|
||||
void add_recv_stats(int fd, int recv) {}
|
||||
void log_socket_close(int fd, short reason) {}
|
||||
void log_socket_connect(int fd, unsigned int ip, unsigned short port) {}
|
||||
#endif
|
0
libs/utils/MODULE_LICENSE_APACHE2
Normal file
0
libs/utils/MODULE_LICENSE_APACHE2
Normal file
46
libs/utils/MemoryBase.cpp
Normal file
46
libs/utils/MemoryBase.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/MemoryBase.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
|
||||
ssize_t offset, size_t size)
|
||||
: mSize(size), mOffset(offset), mHeap(heap)
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
|
||||
{
|
||||
if (offset) *offset = mOffset;
|
||||
if (size) *size = mSize;
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
MemoryBase::~MemoryBase()
|
||||
{
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
409
libs/utils/MemoryDealer.cpp
Normal file
409
libs/utils/MemoryDealer.cpp
Normal file
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "MemoryDealer"
|
||||
|
||||
#include <utils/MemoryDealer.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/SortedVector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/MemoryBase.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class SimpleMemory : public MemoryBase {
|
||||
public:
|
||||
SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
|
||||
virtual ~SimpleMemory();
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
MemoryDealer::Allocation::Allocation(
|
||||
const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
|
||||
const sp<IMemory>& memory)
|
||||
: mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::Allocation::~Allocation()
|
||||
{
|
||||
if (mSize) {
|
||||
/* NOTE: it's VERY important to not free allocations of size 0 because
|
||||
* they're special as they don't have any record in the allocator
|
||||
* and could alias some real allocation (their offset is zero). */
|
||||
mDealer->deallocate(mOffset);
|
||||
}
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
|
||||
ssize_t* offset, size_t* size) const
|
||||
{
|
||||
return mMemory->getMemory(offset, size);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
|
||||
: mHeap(new SharedHeap(size, flags, name)),
|
||||
mAllocator(new SimpleBestFitAllocator(size))
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
|
||||
: mHeap(heap),
|
||||
mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
|
||||
const sp<AllocatorInterface>& allocator)
|
||||
: mHeap(heap), mAllocator(allocator)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDealer::~MemoryDealer()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
|
||||
{
|
||||
sp<IMemory> memory;
|
||||
const ssize_t offset = allocator()->allocate(size, flags);
|
||||
if (offset >= 0) {
|
||||
sp<IMemory> new_memory = heap()->mapMemory(offset, size);
|
||||
if (new_memory != 0) {
|
||||
memory = new Allocation(this, offset, size, new_memory);
|
||||
} else {
|
||||
LOGE("couldn't map [%8x, %d]", offset, size);
|
||||
if (size) {
|
||||
/* NOTE: it's VERY important to not free allocations of size 0
|
||||
* because they're special as they don't have any record in the
|
||||
* allocator and could alias some real allocation
|
||||
* (their offset is zero). */
|
||||
allocator()->deallocate(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
void MemoryDealer::deallocate(size_t offset)
|
||||
{
|
||||
allocator()->deallocate(offset);
|
||||
}
|
||||
|
||||
void MemoryDealer::dump(const char* what, uint32_t flags) const
|
||||
{
|
||||
allocator()->dump(what, flags);
|
||||
}
|
||||
|
||||
const sp<HeapInterface>& MemoryDealer::heap() const {
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
const sp<AllocatorInterface>& MemoryDealer::allocator() const {
|
||||
return mAllocator;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// align all the memory blocks on a cache-line boundary
|
||||
const int SimpleBestFitAllocator::kMemoryAlign = 32;
|
||||
|
||||
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
|
||||
{
|
||||
size_t pagesize = getpagesize();
|
||||
mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
|
||||
|
||||
chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
|
||||
mList.insertHead(node);
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::~SimpleBestFitAllocator()
|
||||
{
|
||||
while(!mList.isEmpty()) {
|
||||
delete mList.remove(mList.head());
|
||||
}
|
||||
}
|
||||
|
||||
size_t SimpleBestFitAllocator::size() const
|
||||
{
|
||||
return mHeapSize;
|
||||
}
|
||||
|
||||
size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
ssize_t offset = alloc(size, flags);
|
||||
return offset;
|
||||
}
|
||||
|
||||
status_t SimpleBestFitAllocator::deallocate(size_t offset)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
chunk_t const * const freed = dealloc(offset);
|
||||
if (freed) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
|
||||
{
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
size = (size + kMemoryAlign-1) / kMemoryAlign;
|
||||
chunk_t* free_chunk = 0;
|
||||
chunk_t* cur = mList.head();
|
||||
|
||||
size_t pagesize = getpagesize();
|
||||
while (cur) {
|
||||
int extra = 0;
|
||||
if (flags & PAGE_ALIGNED)
|
||||
extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
|
||||
|
||||
// best fit
|
||||
if (cur->free && (cur->size >= (size+extra))) {
|
||||
if ((!free_chunk) || (cur->size < free_chunk->size)) {
|
||||
free_chunk = cur;
|
||||
}
|
||||
if (cur->size == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (free_chunk) {
|
||||
const size_t free_size = free_chunk->size;
|
||||
free_chunk->free = 0;
|
||||
free_chunk->size = size;
|
||||
if (free_size > size) {
|
||||
int extra = 0;
|
||||
if (flags & PAGE_ALIGNED)
|
||||
extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
|
||||
if (extra) {
|
||||
chunk_t* split = new chunk_t(free_chunk->start, extra);
|
||||
free_chunk->start += extra;
|
||||
mList.insertBefore(free_chunk, split);
|
||||
}
|
||||
|
||||
LOGE_IF((flags&PAGE_ALIGNED) &&
|
||||
((free_chunk->start*kMemoryAlign)&(pagesize-1)),
|
||||
"PAGE_ALIGNED requested, but page is not aligned!!!");
|
||||
|
||||
const ssize_t tail_free = free_size - (size+extra);
|
||||
if (tail_free > 0) {
|
||||
chunk_t* split = new chunk_t(
|
||||
free_chunk->start + free_chunk->size, tail_free);
|
||||
mList.insertAfter(free_chunk, split);
|
||||
}
|
||||
}
|
||||
return (free_chunk->start)*kMemoryAlign;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
|
||||
{
|
||||
start = start / kMemoryAlign;
|
||||
chunk_t* cur = mList.head();
|
||||
while (cur) {
|
||||
if (cur->start == start) {
|
||||
LOG_FATAL_IF(cur->free,
|
||||
"block at offset 0x%08lX of size 0x%08lX already freed",
|
||||
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
|
||||
|
||||
// merge freed blocks together
|
||||
chunk_t* freed = cur;
|
||||
cur->free = 1;
|
||||
do {
|
||||
chunk_t* const p = cur->prev;
|
||||
chunk_t* const n = cur->next;
|
||||
if (p && (p->free || !cur->size)) {
|
||||
freed = p;
|
||||
p->size += cur->size;
|
||||
mList.remove(cur);
|
||||
delete cur;
|
||||
}
|
||||
cur = n;
|
||||
} while (cur && cur->free);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!freed->free) {
|
||||
dump_l("dealloc (!freed->free)");
|
||||
}
|
||||
#endif
|
||||
LOG_FATAL_IF(!freed->free,
|
||||
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
|
||||
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
|
||||
|
||||
return freed;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
dump_l(what, flags);
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
|
||||
{
|
||||
String8 result;
|
||||
dump_l(result, what, flags);
|
||||
LOGD("%s", result.string());
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump(String8& result,
|
||||
const char* what, uint32_t flags) const
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
dump_l(result, what, flags);
|
||||
}
|
||||
|
||||
void SimpleBestFitAllocator::dump_l(String8& result,
|
||||
const char* what, uint32_t flags) const
|
||||
{
|
||||
size_t size = 0;
|
||||
int32_t i = 0;
|
||||
chunk_t const* cur = mList.head();
|
||||
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
|
||||
what, this, (unsigned int)mHeapSize);
|
||||
|
||||
result.append(buffer);
|
||||
|
||||
while (cur) {
|
||||
const char* errs[] = {"", "| link bogus NP",
|
||||
"| link bogus PN", "| link bogus NP+PN" };
|
||||
int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
|
||||
int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
|
||||
|
||||
snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
|
||||
i, int(cur), int(cur->start*kMemoryAlign),
|
||||
int(cur->size*kMemoryAlign),
|
||||
int(cur->free) ? "F" : "A",
|
||||
errs[np|pn]);
|
||||
|
||||
result.append(buffer);
|
||||
|
||||
if (!cur->free)
|
||||
size += cur->size*kMemoryAlign;
|
||||
|
||||
i++;
|
||||
cur = cur->next;
|
||||
}
|
||||
snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
|
||||
result.append(buffer);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
|
||||
: MemoryHeapBase(size, flags, name)
|
||||
{
|
||||
}
|
||||
|
||||
SharedHeap::~SharedHeap()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
|
||||
{
|
||||
return new SimpleMemory(this, offset, size);
|
||||
}
|
||||
|
||||
|
||||
SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
|
||||
ssize_t offset, size_t size)
|
||||
: MemoryBase(heap, offset, size)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
|
||||
memset(start_ptr, 0xda, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
SimpleMemory::~SimpleMemory()
|
||||
{
|
||||
size_t freedOffset = getOffset();
|
||||
size_t freedSize = getSize();
|
||||
|
||||
// keep the size to unmap in excess
|
||||
size_t pagesize = getpagesize();
|
||||
size_t start = freedOffset;
|
||||
size_t end = start + freedSize;
|
||||
start &= ~(pagesize-1);
|
||||
end = (end + pagesize-1) & ~(pagesize-1);
|
||||
|
||||
// give back to the kernel the pages we don't need
|
||||
size_t free_start = freedOffset;
|
||||
size_t free_end = free_start + freedSize;
|
||||
if (start < free_start)
|
||||
start = free_start;
|
||||
if (end > free_end)
|
||||
end = free_end;
|
||||
start = (start + pagesize-1) & ~(pagesize-1);
|
||||
end &= ~(pagesize-1);
|
||||
|
||||
if (start < end) {
|
||||
void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
|
||||
size_t size = end-start;
|
||||
|
||||
#ifndef NDEBUG
|
||||
memset(start_ptr, 0xdf, size);
|
||||
#endif
|
||||
|
||||
// MADV_REMOVE is not defined on Dapper based Goobuntu
|
||||
#ifdef MADV_REMOVE
|
||||
if (size) {
|
||||
int err = madvise(start_ptr, size, MADV_REMOVE);
|
||||
LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
|
||||
start_ptr, size, err<0 ? strerror(errno) : "Ok");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
183
libs/utils/MemoryHeapBase.cpp
Normal file
183
libs/utils/MemoryHeapBase.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "MemoryHeapBase"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <cutils/ashmem.h>
|
||||
#include <cutils/atomic.h>
|
||||
|
||||
#include <utils/MemoryHeapBase.h>
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
#include <linux/android_pmem.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase()
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED),
|
||||
mDevice(NULL), mNeedUnmap(false)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
|
||||
mDevice(0), mNeedUnmap(false)
|
||||
{
|
||||
const size_t pagesize = getpagesize();
|
||||
size = ((size + pagesize-1) & ~(pagesize-1));
|
||||
int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
|
||||
LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
|
||||
if (fd >= 0) {
|
||||
if (mapfd(fd, size) == NO_ERROR) {
|
||||
if (flags & READ_ONLY) {
|
||||
ashmem_set_prot_region(fd, PROT_READ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
|
||||
mDevice(0), mNeedUnmap(false)
|
||||
{
|
||||
int fd = open(device, O_RDWR);
|
||||
LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
|
||||
if (fd >= 0) {
|
||||
const size_t pagesize = getpagesize();
|
||||
size = ((size + pagesize-1) & ~(pagesize-1));
|
||||
if (mapfd(fd, size) == NO_ERROR) {
|
||||
mDevice = device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
|
||||
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
|
||||
mDevice(0), mNeedUnmap(false)
|
||||
{
|
||||
const size_t pagesize = getpagesize();
|
||||
size = ((size + pagesize-1) & ~(pagesize-1));
|
||||
mapfd(dup(fd), size);
|
||||
}
|
||||
|
||||
status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
|
||||
{
|
||||
if (mFD != -1) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
mFD = fd;
|
||||
mBase = base;
|
||||
mSize = size;
|
||||
mFlags = flags;
|
||||
mDevice = device;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t MemoryHeapBase::mapfd(int fd, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
// try to figure out the size automatically
|
||||
#if HAVE_ANDROID_OS
|
||||
// first try the PMEM ioctl
|
||||
pmem_region reg;
|
||||
int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®);
|
||||
if (err == 0)
|
||||
size = reg.len;
|
||||
#endif
|
||||
if (size == 0) { // try fstat
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == 0)
|
||||
size = sb.st_size;
|
||||
}
|
||||
// if it didn't work, let mmap() fail.
|
||||
}
|
||||
|
||||
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
|
||||
void* base = (uint8_t*)mmap(0, size,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
LOGE("mmap(fd=%d, size=%u) failed (%s)",
|
||||
fd, uint32_t(size), strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
//LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
|
||||
mBase = base;
|
||||
mNeedUnmap = true;
|
||||
} else {
|
||||
mBase = 0; // not MAP_FAILED
|
||||
mNeedUnmap = false;
|
||||
}
|
||||
mFD = fd;
|
||||
mSize = size;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
MemoryHeapBase::~MemoryHeapBase()
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
void MemoryHeapBase::dispose()
|
||||
{
|
||||
int fd = android_atomic_or(-1, &mFD);
|
||||
if (fd >= 0) {
|
||||
if (mNeedUnmap) {
|
||||
//LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
|
||||
munmap(mBase, mSize);
|
||||
}
|
||||
mBase = 0;
|
||||
mSize = 0;
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int MemoryHeapBase::getHeapID() const {
|
||||
return mFD;
|
||||
}
|
||||
|
||||
void* MemoryHeapBase::getBase() const {
|
||||
return mBase;
|
||||
}
|
||||
|
||||
size_t MemoryHeapBase::getSize() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
uint32_t MemoryHeapBase::getFlags() const {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
const char* MemoryHeapBase::getDevice() const {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
248
libs/utils/MemoryHeapPmem.cpp
Normal file
248
libs/utils/MemoryHeapPmem.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "MemoryHeapPmem"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <utils/MemoryHeapPmem.h>
|
||||
#include <utils/MemoryHeapBase.h>
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
#include <linux/android_pmem.h>
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
|
||||
: BnMemory(), mClientHeap(heap)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
|
||||
if (mClientHeap != NULL) {
|
||||
mClientHeap->remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
|
||||
public:
|
||||
SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
|
||||
virtual ~SubRegionMemory();
|
||||
virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
|
||||
private:
|
||||
friend class MemoryHeapPmem;
|
||||
void revoke();
|
||||
size_t mSize;
|
||||
ssize_t mOffset;
|
||||
};
|
||||
|
||||
SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
|
||||
ssize_t offset, size_t size)
|
||||
: MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
|
||||
memset(start_ptr, 0xda, size);
|
||||
#endif
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
if (size > 0) {
|
||||
const size_t pagesize = getpagesize();
|
||||
size = (size + pagesize-1) & ~(pagesize-1);
|
||||
int our_fd = heap->heapID();
|
||||
struct pmem_region sub = { offset, size };
|
||||
int err = ioctl(our_fd, PMEM_MAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_MAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
|
||||
{
|
||||
if (offset) *offset = mOffset;
|
||||
if (size) *size = mSize;
|
||||
return getHeap();
|
||||
}
|
||||
|
||||
SubRegionMemory::~SubRegionMemory()
|
||||
{
|
||||
revoke();
|
||||
}
|
||||
|
||||
|
||||
void SubRegionMemory::revoke()
|
||||
{
|
||||
// NOTE: revoke() doesn't need to be protected by a lock because it
|
||||
// can only be called from MemoryHeapPmem::revoke(), which means
|
||||
// that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
|
||||
// which means MemoryHeapPmem::revoke() wouldn't have been able to
|
||||
// promote() it.
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
if (mSize != NULL) {
|
||||
const sp<MemoryHeapPmem>& heap(getHeap());
|
||||
int our_fd = heap->heapID();
|
||||
struct pmem_region sub;
|
||||
sub.offset = mOffset;
|
||||
sub.len = mSize;
|
||||
int err = ioctl(our_fd, PMEM_UNMAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
mSize = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
|
||||
uint32_t flags)
|
||||
: HeapInterface(), MemoryHeapBase()
|
||||
{
|
||||
char const * const device = pmemHeap->getDevice();
|
||||
#if HAVE_ANDROID_OS
|
||||
if (device) {
|
||||
int fd = open(device, O_RDWR);
|
||||
LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
|
||||
if (fd >= 0) {
|
||||
int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
|
||||
if (err < 0) {
|
||||
LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
|
||||
strerror(errno), fd, pmemHeap->heapID());
|
||||
close(fd);
|
||||
} else {
|
||||
// everything went well...
|
||||
mParentHeap = pmemHeap;
|
||||
MemoryHeapBase::init(fd,
|
||||
pmemHeap->getBase(),
|
||||
pmemHeap->getSize(),
|
||||
pmemHeap->getFlags() | flags,
|
||||
device);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
mParentHeap = pmemHeap;
|
||||
MemoryHeapBase::init(
|
||||
dup(pmemHeap->heapID()),
|
||||
pmemHeap->getBase(),
|
||||
pmemHeap->getSize(),
|
||||
pmemHeap->getFlags() | flags,
|
||||
device);
|
||||
#endif
|
||||
}
|
||||
|
||||
MemoryHeapPmem::~MemoryHeapPmem()
|
||||
{
|
||||
}
|
||||
|
||||
sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
|
||||
{
|
||||
sp<MemoryPmem> memory = createMemory(offset, size);
|
||||
if (memory != 0) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
mAllocations.add(memory);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
sp<SubRegionMemory> memory;
|
||||
if (heapID() > 0)
|
||||
memory = new SubRegionMemory(this, offset, size);
|
||||
return memory;
|
||||
}
|
||||
|
||||
status_t MemoryHeapPmem::slap()
|
||||
{
|
||||
#if HAVE_ANDROID_OS
|
||||
size_t size = getSize();
|
||||
const size_t pagesize = getpagesize();
|
||||
size = (size + pagesize-1) & ~(pagesize-1);
|
||||
int our_fd = getHeapID();
|
||||
struct pmem_region sub = { 0, size };
|
||||
int err = ioctl(our_fd, PMEM_MAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_MAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
return -errno;
|
||||
#else
|
||||
return NO_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
status_t MemoryHeapPmem::unslap()
|
||||
{
|
||||
#if HAVE_ANDROID_OS
|
||||
size_t size = getSize();
|
||||
const size_t pagesize = getpagesize();
|
||||
size = (size + pagesize-1) & ~(pagesize-1);
|
||||
int our_fd = getHeapID();
|
||||
struct pmem_region sub = { 0, size };
|
||||
int err = ioctl(our_fd, PMEM_UNMAP, &sub);
|
||||
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
|
||||
"mFD=%d, sub.offset=%lu, sub.size=%lu",
|
||||
strerror(errno), our_fd, sub.offset, sub.len);
|
||||
return -errno;
|
||||
#else
|
||||
return NO_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryHeapPmem::revoke()
|
||||
{
|
||||
SortedVector< wp<MemoryPmem> > allocations;
|
||||
|
||||
{ // scope for lock
|
||||
Mutex::Autolock _l(mLock);
|
||||
allocations = mAllocations;
|
||||
}
|
||||
|
||||
ssize_t count = allocations.size();
|
||||
for (ssize_t i=0 ; i<count ; i++) {
|
||||
sp<MemoryPmem> memory(allocations[i].promote());
|
||||
if (memory != 0)
|
||||
memory->revoke();
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
mAllocations.remove(memory);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
190
libs/utils/NOTICE
Normal file
190
libs/utils/NOTICE
Normal file
|
@ -0,0 +1,190 @@
|
|||
|
||||
Copyright (c) 2005-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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
|
1377
libs/utils/Parcel.cpp
Normal file
1377
libs/utils/Parcel.cpp
Normal file
File diff suppressed because it is too large
Load diff
465
libs/utils/Pipe.cpp
Normal file
465
libs/utils/Pipe.cpp
Normal file
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Unidirectional pipe.
|
||||
//
|
||||
|
||||
#include <utils/Pipe.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
const unsigned long kInvalidHandle = (unsigned long) -1;
|
||||
|
||||
|
||||
/*
|
||||
* Constructor. Do little.
|
||||
*/
|
||||
Pipe::Pipe(void)
|
||||
: mReadNonBlocking(false), mReadHandle(kInvalidHandle),
|
||||
mWriteHandle(kInvalidHandle)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor. Use the system-appropriate close call.
|
||||
*/
|
||||
Pipe::~Pipe(void)
|
||||
{
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
if (mReadHandle != kInvalidHandle) {
|
||||
if (!CloseHandle((HANDLE)mReadHandle))
|
||||
LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
|
||||
mReadHandle);
|
||||
}
|
||||
if (mWriteHandle != kInvalidHandle) {
|
||||
FlushFileBuffers((HANDLE)mWriteHandle);
|
||||
if (!CloseHandle((HANDLE)mWriteHandle))
|
||||
LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
|
||||
mWriteHandle);
|
||||
}
|
||||
#else
|
||||
if (mReadHandle != kInvalidHandle) {
|
||||
if (close((int) mReadHandle) != 0)
|
||||
LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
|
||||
(int) mReadHandle);
|
||||
}
|
||||
if (mWriteHandle != kInvalidHandle) {
|
||||
if (close((int) mWriteHandle) != 0)
|
||||
LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
|
||||
(int) mWriteHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the pipe.
|
||||
*
|
||||
* Use the POSIX stuff for everything but Windows.
|
||||
*/
|
||||
bool Pipe::create(void)
|
||||
{
|
||||
assert(mReadHandle == kInvalidHandle);
|
||||
assert(mWriteHandle == kInvalidHandle);
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
/* we use this across processes, so they need to be inheritable */
|
||||
HANDLE handles[2];
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
|
||||
LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
|
||||
return false;
|
||||
}
|
||||
mReadHandle = (unsigned long) handles[0];
|
||||
mWriteHandle = (unsigned long) handles[1];
|
||||
return true;
|
||||
#else
|
||||
int fds[2];
|
||||
|
||||
if (pipe(fds) != 0) {
|
||||
LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
|
||||
return false;
|
||||
}
|
||||
mReadHandle = fds[0];
|
||||
mWriteHandle = fds[1];
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a "half pipe". Please, no Segway riding.
|
||||
*/
|
||||
bool Pipe::createReader(unsigned long handle)
|
||||
{
|
||||
mReadHandle = handle;
|
||||
assert(mWriteHandle == kInvalidHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a "half pipe" for writing.
|
||||
*/
|
||||
bool Pipe::createWriter(unsigned long handle)
|
||||
{
|
||||
mWriteHandle = handle;
|
||||
assert(mReadHandle == kInvalidHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return "true" if create() has been called successfully.
|
||||
*/
|
||||
bool Pipe::isCreated(void)
|
||||
{
|
||||
// one or the other should be open
|
||||
return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read data from the pipe.
|
||||
*
|
||||
* For Linux and Darwin, just call read(). For Windows, implement
|
||||
* non-blocking reads by calling PeekNamedPipe first.
|
||||
*/
|
||||
int Pipe::read(void* buf, int count)
|
||||
{
|
||||
assert(mReadHandle != kInvalidHandle);
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
DWORD totalBytesAvail = count;
|
||||
DWORD bytesRead;
|
||||
|
||||
if (mReadNonBlocking) {
|
||||
// use PeekNamedPipe to adjust read count expectations
|
||||
if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
|
||||
&totalBytesAvail, NULL))
|
||||
{
|
||||
LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (totalBytesAvail == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
|
||||
NULL))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
|
||||
return 0;
|
||||
LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) bytesRead;
|
||||
#else
|
||||
int cc;
|
||||
cc = ::read(mReadHandle, buf, count);
|
||||
if (cc < 0 && errno == EAGAIN)
|
||||
return 0;
|
||||
return cc;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data to the pipe.
|
||||
*
|
||||
* POSIX systems are trivial, Windows uses a different call and doesn't
|
||||
* handle non-blocking writes.
|
||||
*
|
||||
* If we add non-blocking support here, we probably want to make it an
|
||||
* all-or-nothing write.
|
||||
*
|
||||
* DO NOT use LOG() here, we could be writing a log message.
|
||||
*/
|
||||
int Pipe::write(const void* buf, int count)
|
||||
{
|
||||
assert(mWriteHandle != kInvalidHandle);
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
DWORD bytesWritten;
|
||||
|
||||
if (mWriteNonBlocking) {
|
||||
// BUG: can't use PeekNamedPipe() to get the amount of space
|
||||
// left. Looks like we need to use "overlapped I/O" functions.
|
||||
// I just don't care that much.
|
||||
}
|
||||
|
||||
if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
|
||||
// can't LOG, use stderr
|
||||
fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) bytesWritten;
|
||||
#else
|
||||
int cc;
|
||||
cc = ::write(mWriteHandle, buf, count);
|
||||
if (cc < 0 && errno == EAGAIN)
|
||||
return 0;
|
||||
return cc;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out if there is data available on the read fd.
|
||||
*
|
||||
* We return "true" on error because we want the caller to try to read
|
||||
* from the pipe. They'll notice the read failure and do something
|
||||
* appropriate.
|
||||
*/
|
||||
bool Pipe::readReady(void)
|
||||
{
|
||||
assert(mReadHandle != kInvalidHandle);
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
DWORD totalBytesAvail;
|
||||
|
||||
if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
|
||||
&totalBytesAvail, NULL))
|
||||
{
|
||||
LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return (totalBytesAvail != 0);
|
||||
#else
|
||||
errno = 0;
|
||||
fd_set readfds;
|
||||
struct timeval tv = { 0, 0 };
|
||||
int cc;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(mReadHandle, &readfds);
|
||||
|
||||
cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
|
||||
if (cc < 0) {
|
||||
LOG(LOG_ERROR, "pipe", "select() failed\n");
|
||||
return true;
|
||||
} else if (cc == 0) {
|
||||
/* timed out, nothing available */
|
||||
return false;
|
||||
} else if (cc == 1) {
|
||||
/* our fd is ready */
|
||||
return true;
|
||||
} else {
|
||||
LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or disable non-blocking mode for the read descriptor.
|
||||
*
|
||||
* NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
|
||||
* actually be in non-blocking mode. If this matters -- i.e. you're not
|
||||
* using a select() call -- put a call to readReady() in front of the
|
||||
* ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
|
||||
* Darwin.
|
||||
*/
|
||||
bool Pipe::setReadNonBlocking(bool val)
|
||||
{
|
||||
assert(mReadHandle != kInvalidHandle);
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
// nothing to do
|
||||
#else
|
||||
int flags;
|
||||
|
||||
if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
|
||||
LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
|
||||
return false;
|
||||
}
|
||||
if (val)
|
||||
flags |= O_NONBLOCK;
|
||||
else
|
||||
flags &= ~(O_NONBLOCK);
|
||||
if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
|
||||
LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
mReadNonBlocking = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or disable non-blocking mode for the write descriptor.
|
||||
*
|
||||
* As with setReadNonBlocking(), this does not work on the Mac.
|
||||
*/
|
||||
bool Pipe::setWriteNonBlocking(bool val)
|
||||
{
|
||||
assert(mWriteHandle != kInvalidHandle);
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
// nothing to do
|
||||
#else
|
||||
int flags;
|
||||
|
||||
if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
|
||||
LOG(LOG_WARN, "pipe",
|
||||
"Warning: couldn't get flags for pipe write fd (errno=%d)\n",
|
||||
errno);
|
||||
return false;
|
||||
}
|
||||
if (val)
|
||||
flags |= O_NONBLOCK;
|
||||
else
|
||||
flags &= ~(O_NONBLOCK);
|
||||
if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
|
||||
LOG(LOG_WARN, "pipe",
|
||||
"Warning: couldn't set flags for pipe write fd (errno=%d)\n",
|
||||
errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
mWriteNonBlocking = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specify whether a file descriptor can be inherited by a child process.
|
||||
* Under Linux this means setting the close-on-exec flag, under Windows
|
||||
* this is SetHandleInformation(HANDLE_FLAG_INHERIT).
|
||||
*/
|
||||
bool Pipe::disallowReadInherit(void)
|
||||
{
|
||||
if (mReadHandle == kInvalidHandle)
|
||||
return false;
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
|
||||
return false;
|
||||
#else
|
||||
if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
bool Pipe::disallowWriteInherit(void)
|
||||
{
|
||||
if (mWriteHandle == kInvalidHandle)
|
||||
return false;
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
|
||||
return false;
|
||||
#else
|
||||
if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close read descriptor.
|
||||
*/
|
||||
bool Pipe::closeRead(void)
|
||||
{
|
||||
if (mReadHandle == kInvalidHandle)
|
||||
return false;
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
if (mReadHandle != kInvalidHandle) {
|
||||
if (!CloseHandle((HANDLE)mReadHandle)) {
|
||||
LOG(LOG_WARN, "pipe", "failed closing read handle\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (mReadHandle != kInvalidHandle) {
|
||||
if (close((int) mReadHandle) != 0) {
|
||||
LOG(LOG_WARN, "pipe", "failed closing read fd\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mReadHandle = kInvalidHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close write descriptor.
|
||||
*/
|
||||
bool Pipe::closeWrite(void)
|
||||
{
|
||||
if (mWriteHandle == kInvalidHandle)
|
||||
return false;
|
||||
|
||||
#if defined(HAVE_WIN32_IPC)
|
||||
if (mWriteHandle != kInvalidHandle) {
|
||||
if (!CloseHandle((HANDLE)mWriteHandle)) {
|
||||
LOG(LOG_WARN, "pipe", "failed closing write handle\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (mWriteHandle != kInvalidHandle) {
|
||||
if (close((int) mWriteHandle) != 0) {
|
||||
LOG(LOG_WARN, "pipe", "failed closing write fd\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mWriteHandle = kInvalidHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the read handle.
|
||||
*/
|
||||
unsigned long Pipe::getReadHandle(void)
|
||||
{
|
||||
assert(mReadHandle != kInvalidHandle);
|
||||
|
||||
return mReadHandle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the write handle.
|
||||
*/
|
||||
unsigned long Pipe::getWriteHandle(void)
|
||||
{
|
||||
assert(mWriteHandle != kInvalidHandle);
|
||||
|
||||
return mWriteHandle;
|
||||
}
|
||||
|
398
libs/utils/ProcessState.cpp
Normal file
398
libs/utils/ProcessState.cpp
Normal file
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "ProcessState"
|
||||
|
||||
#include <cutils/process_name.h>
|
||||
|
||||
#include <utils/ProcessState.h>
|
||||
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/BpBinder.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/IServiceManager.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <private/utils/binder_module.h>
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define BINDER_VM_SIZE (1*1024*1024)
|
||||
|
||||
static bool gSingleProcess = false;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
// Global variables
|
||||
int mArgC;
|
||||
const char* const* mArgV;
|
||||
int mArgLen;
|
||||
|
||||
class PoolThread : public Thread
|
||||
{
|
||||
public:
|
||||
PoolThread(bool isMain)
|
||||
: mIsMain(isMain)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool threadLoop()
|
||||
{
|
||||
IPCThreadState::self()->joinThreadPool(mIsMain);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool mIsMain;
|
||||
};
|
||||
|
||||
sp<ProcessState> ProcessState::self()
|
||||
{
|
||||
if (gProcess != NULL) return gProcess;
|
||||
|
||||
AutoMutex _l(gProcessMutex);
|
||||
if (gProcess == NULL) gProcess = new ProcessState;
|
||||
return gProcess;
|
||||
}
|
||||
|
||||
void ProcessState::setSingleProcess(bool singleProcess)
|
||||
{
|
||||
gSingleProcess = singleProcess;
|
||||
}
|
||||
|
||||
|
||||
void ProcessState::setContextObject(const sp<IBinder>& object)
|
||||
{
|
||||
setContextObject(object, String16("default"));
|
||||
}
|
||||
|
||||
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
|
||||
{
|
||||
if (supportsProcesses()) {
|
||||
return getStrongProxyForHandle(0);
|
||||
} else {
|
||||
return getContextObject(String16("default"), caller);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
mContexts.add(name, object);
|
||||
}
|
||||
|
||||
sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
|
||||
{
|
||||
mLock.lock();
|
||||
sp<IBinder> object(
|
||||
mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
|
||||
mLock.unlock();
|
||||
|
||||
//printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
|
||||
|
||||
if (object != NULL) return object;
|
||||
|
||||
// Don't attempt to retrieve contexts if we manage them
|
||||
if (mManagesContexts) {
|
||||
LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
|
||||
String8(name).string());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
{
|
||||
Parcel data, reply;
|
||||
// no interface token on this magic transaction
|
||||
data.writeString16(name);
|
||||
data.writeStrongBinder(caller);
|
||||
status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
|
||||
if (result == NO_ERROR) {
|
||||
object = reply.readStrongBinder();
|
||||
}
|
||||
}
|
||||
|
||||
ipc->flushCommands();
|
||||
|
||||
if (object != NULL) setContextObject(object, name);
|
||||
return object;
|
||||
}
|
||||
|
||||
bool ProcessState::supportsProcesses() const
|
||||
{
|
||||
return mDriverFD >= 0;
|
||||
}
|
||||
|
||||
void ProcessState::startThreadPool()
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
if (!mThreadPoolStarted) {
|
||||
mThreadPoolStarted = true;
|
||||
spawnPooledThread(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessState::isContextManager(void) const
|
||||
{
|
||||
return mManagesContexts;
|
||||
}
|
||||
|
||||
bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
|
||||
{
|
||||
if (!mManagesContexts) {
|
||||
AutoMutex _l(mLock);
|
||||
mBinderContextCheckFunc = checkFunc;
|
||||
mBinderContextUserData = userData;
|
||||
if (mDriverFD >= 0) {
|
||||
int dummy = 0;
|
||||
#if defined(HAVE_ANDROID_OS)
|
||||
status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
|
||||
#else
|
||||
status_t result = INVALID_OPERATION;
|
||||
#endif
|
||||
if (result == 0) {
|
||||
mManagesContexts = true;
|
||||
} else if (result == -1) {
|
||||
mBinderContextCheckFunc = NULL;
|
||||
mBinderContextUserData = NULL;
|
||||
LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
// If there is no driver, our only world is the local
|
||||
// process so we can always become the context manager there.
|
||||
mManagesContexts = true;
|
||||
}
|
||||
}
|
||||
return mManagesContexts;
|
||||
}
|
||||
|
||||
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
|
||||
{
|
||||
const size_t N=mHandleToObject.size();
|
||||
if (N <= (size_t)handle) {
|
||||
handle_entry e;
|
||||
e.binder = NULL;
|
||||
e.refs = NULL;
|
||||
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
|
||||
if (err < NO_ERROR) return NULL;
|
||||
}
|
||||
return &mHandleToObject.editItemAt(handle);
|
||||
}
|
||||
|
||||
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
|
||||
{
|
||||
sp<IBinder> result;
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
handle_entry* e = lookupHandleLocked(handle);
|
||||
|
||||
if (e != NULL) {
|
||||
// We need to create a new BpBinder if there isn't currently one, OR we
|
||||
// are unable to acquire a weak reference on this current one. See comment
|
||||
// in getWeakProxyForHandle() for more info about this.
|
||||
IBinder* b = e->binder;
|
||||
if (b == NULL || !e->refs->attemptIncWeak(this)) {
|
||||
b = new BpBinder(handle);
|
||||
e->binder = b;
|
||||
if (b) e->refs = b->getWeakRefs();
|
||||
result = b;
|
||||
} else {
|
||||
// This little bit of nastyness is to allow us to add a primary
|
||||
// reference to the remote proxy when this team doesn't have one
|
||||
// but another team is sending the handle to us.
|
||||
result.force_set(b);
|
||||
e->refs->decWeak(this);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
|
||||
{
|
||||
wp<IBinder> result;
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
handle_entry* e = lookupHandleLocked(handle);
|
||||
|
||||
if (e != NULL) {
|
||||
// We need to create a new BpBinder if there isn't currently one, OR we
|
||||
// are unable to acquire a weak reference on this current one. The
|
||||
// attemptIncWeak() is safe because we know the BpBinder destructor will always
|
||||
// call expungeHandle(), which acquires the same lock we are holding now.
|
||||
// We need to do this because there is a race condition between someone
|
||||
// releasing a reference on this BpBinder, and a new reference on its handle
|
||||
// arriving from the driver.
|
||||
IBinder* b = e->binder;
|
||||
if (b == NULL || !e->refs->attemptIncWeak(this)) {
|
||||
b = new BpBinder(handle);
|
||||
result = b;
|
||||
e->binder = b;
|
||||
if (b) e->refs = b->getWeakRefs();
|
||||
} else {
|
||||
result = b;
|
||||
e->refs->decWeak(this);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
handle_entry* e = lookupHandleLocked(handle);
|
||||
|
||||
// This handle may have already been replaced with a new BpBinder
|
||||
// (if someone failed the AttemptIncWeak() above); we don't want
|
||||
// to overwrite it.
|
||||
if (e && e->binder == binder) e->binder = NULL;
|
||||
}
|
||||
|
||||
void ProcessState::setArgs(int argc, const char* const argv[])
|
||||
{
|
||||
mArgC = argc;
|
||||
mArgV = (const char **)argv;
|
||||
|
||||
mArgLen = 0;
|
||||
for (int i=0; i<argc; i++) {
|
||||
mArgLen += strlen(argv[i]) + 1;
|
||||
}
|
||||
mArgLen--;
|
||||
}
|
||||
|
||||
int ProcessState::getArgC() const
|
||||
{
|
||||
return mArgC;
|
||||
}
|
||||
|
||||
const char* const* ProcessState::getArgV() const
|
||||
{
|
||||
return mArgV;
|
||||
}
|
||||
|
||||
void ProcessState::setArgV0(const char* txt)
|
||||
{
|
||||
if (mArgV != NULL) {
|
||||
strncpy((char*)mArgV[0], txt, mArgLen);
|
||||
set_process_name(txt);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessState::spawnPooledThread(bool isMain)
|
||||
{
|
||||
if (mThreadPoolStarted) {
|
||||
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
|
||||
char buf[32];
|
||||
sprintf(buf, "Binder Thread #%d", s);
|
||||
LOGV("Spawning new pooled thread, name=%s\n", buf);
|
||||
sp<Thread> t = new PoolThread(isMain);
|
||||
t->run(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static int open_driver()
|
||||
{
|
||||
if (gSingleProcess) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = open("/dev/binder", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
int vers;
|
||||
#if defined(HAVE_ANDROID_OS)
|
||||
status_t result = ioctl(fd, BINDER_VERSION, &vers);
|
||||
#else
|
||||
status_t result = -1;
|
||||
errno = EPERM;
|
||||
#endif
|
||||
if (result == -1) {
|
||||
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
|
||||
LOGE("Binder driver protocol does not match user space protocol!");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
#if defined(HAVE_ANDROID_OS)
|
||||
size_t maxThreads = 15;
|
||||
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
|
||||
if (result == -1) {
|
||||
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ProcessState::ProcessState()
|
||||
: mDriverFD(open_driver())
|
||||
, mVMStart(MAP_FAILED)
|
||||
, mManagesContexts(false)
|
||||
, mBinderContextCheckFunc(NULL)
|
||||
, mBinderContextUserData(NULL)
|
||||
, mThreadPoolStarted(false)
|
||||
, mThreadPoolSeq(1)
|
||||
{
|
||||
if (mDriverFD >= 0) {
|
||||
// XXX Ideally, there should be a specific define for whether we
|
||||
// have mmap (or whether we could possibly have the kernel module
|
||||
// availabla).
|
||||
#if !defined(HAVE_WIN32_IPC)
|
||||
// mmap the binder, providing a chunk of virtual address space to receive transactions.
|
||||
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
|
||||
if (mVMStart == MAP_FAILED) {
|
||||
// *sigh*
|
||||
LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
|
||||
close(mDriverFD);
|
||||
mDriverFD = -1;
|
||||
}
|
||||
#else
|
||||
mDriverFD = -1;
|
||||
#endif
|
||||
}
|
||||
if (mDriverFD < 0) {
|
||||
// Need to run without the driver, starting our own thread pool.
|
||||
}
|
||||
}
|
||||
|
||||
ProcessState::~ProcessState()
|
||||
{
|
||||
}
|
||||
|
||||
}; // namespace android
|
14
libs/utils/README
Normal file
14
libs/utils/README
Normal file
|
@ -0,0 +1,14 @@
|
|||
Android Utility Function Library
|
||||
|
||||
If you need a feature that is native to Linux but not present on other
|
||||
platforms, construct a platform-dependent implementation that shares
|
||||
the Linux interface. That way the actual device runs as "light" as
|
||||
possible.
|
||||
|
||||
If that isn't feasible, create a system-independent interface and hide
|
||||
the details.
|
||||
|
||||
The ultimate goal is *not* to create a super-duper platform abstraction
|
||||
layer. The goal is to provide an optimized solution for Linux with
|
||||
reasonable implementations for other platforms.
|
||||
|
534
libs/utils/RefBase.cpp
Normal file
534
libs/utils/RefBase.cpp
Normal file
|
@ -0,0 +1,534 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "RefBase"
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include <utils/Atomic.h>
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <typeinfo>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// compile with refcounting debugging enabled
|
||||
#define DEBUG_REFS 0
|
||||
#define DEBUG_REFS_ENABLED_BY_DEFAULT 1
|
||||
#define DEBUG_REFS_CALLSTACK_ENABLED 1
|
||||
|
||||
// log all reference counting operations
|
||||
#define PRINT_REFS 0
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
#define INITIAL_STRONG_VALUE (1<<28)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class RefBase::weakref_impl : public RefBase::weakref_type
|
||||
{
|
||||
public:
|
||||
volatile int32_t mStrong;
|
||||
volatile int32_t mWeak;
|
||||
RefBase* const mBase;
|
||||
volatile int32_t mFlags;
|
||||
|
||||
|
||||
#if !DEBUG_REFS
|
||||
|
||||
weakref_impl(RefBase* base)
|
||||
: mStrong(INITIAL_STRONG_VALUE)
|
||||
, mWeak(0)
|
||||
, mBase(base)
|
||||
, mFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
void addStrongRef(const void* /*id*/) { }
|
||||
void removeStrongRef(const void* /*id*/) { }
|
||||
void addWeakRef(const void* /*id*/) { }
|
||||
void removeWeakRef(const void* /*id*/) { }
|
||||
void printRefs() const { }
|
||||
void trackMe(bool, bool) { }
|
||||
|
||||
#else
|
||||
|
||||
weakref_impl(RefBase* base)
|
||||
: mStrong(INITIAL_STRONG_VALUE)
|
||||
, mWeak(0)
|
||||
, mBase(base)
|
||||
, mFlags(0)
|
||||
, mStrongRefs(NULL)
|
||||
, mWeakRefs(NULL)
|
||||
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
|
||||
, mRetain(false)
|
||||
{
|
||||
//LOGI("NEW weakref_impl %p for RefBase %p", this, base);
|
||||
}
|
||||
|
||||
~weakref_impl()
|
||||
{
|
||||
LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
|
||||
LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
|
||||
}
|
||||
|
||||
void addStrongRef(const void* id)
|
||||
{
|
||||
addRef(&mStrongRefs, id, mStrong);
|
||||
}
|
||||
|
||||
void removeStrongRef(const void* id)
|
||||
{
|
||||
if (!mRetain)
|
||||
removeRef(&mStrongRefs, id);
|
||||
else
|
||||
addRef(&mStrongRefs, id, -mStrong);
|
||||
}
|
||||
|
||||
void addWeakRef(const void* id)
|
||||
{
|
||||
addRef(&mWeakRefs, id, mWeak);
|
||||
}
|
||||
|
||||
void removeWeakRef(const void* id)
|
||||
{
|
||||
if (!mRetain)
|
||||
removeRef(&mWeakRefs, id);
|
||||
else
|
||||
addRef(&mWeakRefs, id, -mWeak);
|
||||
}
|
||||
|
||||
void trackMe(bool track, bool retain)
|
||||
{
|
||||
mTrackEnabled = track;
|
||||
mRetain = retain;
|
||||
}
|
||||
|
||||
void printRefs() const
|
||||
{
|
||||
String8 text;
|
||||
|
||||
{
|
||||
AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
|
||||
|
||||
char buf[128];
|
||||
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
|
||||
text.append(buf);
|
||||
printRefsLocked(&text, mStrongRefs);
|
||||
sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
|
||||
text.append(buf);
|
||||
printRefsLocked(&text, mWeakRefs);
|
||||
}
|
||||
|
||||
{
|
||||
char name[100];
|
||||
snprintf(name, 100, "/data/%p.stack", this);
|
||||
int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
|
||||
if (rc >= 0) {
|
||||
write(rc, text.string(), text.length());
|
||||
close(rc);
|
||||
LOGD("STACK TRACE for %p saved in %s", this, name);
|
||||
}
|
||||
else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
|
||||
name, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct ref_entry
|
||||
{
|
||||
ref_entry* next;
|
||||
const void* id;
|
||||
#if DEBUG_REFS_CALLSTACK_ENABLED
|
||||
CallStack stack;
|
||||
#endif
|
||||
int32_t ref;
|
||||
};
|
||||
|
||||
void addRef(ref_entry** refs, const void* id, int32_t mRef)
|
||||
{
|
||||
if (mTrackEnabled) {
|
||||
AutoMutex _l(mMutex);
|
||||
ref_entry* ref = new ref_entry;
|
||||
// Reference count at the time of the snapshot, but before the
|
||||
// update. Positive value means we increment, negative--we
|
||||
// decrement the reference count.
|
||||
ref->ref = mRef;
|
||||
ref->id = id;
|
||||
#if DEBUG_REFS_CALLSTACK_ENABLED
|
||||
ref->stack.update(2);
|
||||
#endif
|
||||
|
||||
ref->next = *refs;
|
||||
*refs = ref;
|
||||
}
|
||||
}
|
||||
|
||||
void removeRef(ref_entry** refs, const void* id)
|
||||
{
|
||||
if (mTrackEnabled) {
|
||||
AutoMutex _l(mMutex);
|
||||
|
||||
ref_entry* ref = *refs;
|
||||
while (ref != NULL) {
|
||||
if (ref->id == id) {
|
||||
*refs = ref->next;
|
||||
delete ref;
|
||||
return;
|
||||
}
|
||||
|
||||
refs = &ref->next;
|
||||
ref = *refs;
|
||||
}
|
||||
|
||||
LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
|
||||
id, mBase, this);
|
||||
}
|
||||
}
|
||||
|
||||
void printRefsLocked(String8* out, const ref_entry* refs) const
|
||||
{
|
||||
char buf[128];
|
||||
while (refs) {
|
||||
char inc = refs->ref >= 0 ? '+' : '-';
|
||||
sprintf(buf, "\t%c ID %p (ref %d):\n",
|
||||
inc, refs->id, refs->ref);
|
||||
out->append(buf);
|
||||
#if DEBUG_REFS_CALLSTACK_ENABLED
|
||||
out->append(refs->stack.toString("\t\t"));
|
||||
#else
|
||||
out->append("\t\t(call stacks disabled)");
|
||||
#endif
|
||||
refs = refs->next;
|
||||
}
|
||||
}
|
||||
|
||||
Mutex mMutex;
|
||||
ref_entry* mStrongRefs;
|
||||
ref_entry* mWeakRefs;
|
||||
|
||||
bool mTrackEnabled;
|
||||
// Collect stack traces on addref and removeref, instead of deleting the stack references
|
||||
// on removeref that match the address ones.
|
||||
bool mRetain;
|
||||
|
||||
#if 0
|
||||
void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
|
||||
{
|
||||
AutoMutex _l(mMutex);
|
||||
ssize_t i = refs->indexOfKey(id);
|
||||
if (i >= 0) {
|
||||
++(refs->editValueAt(i));
|
||||
} else {
|
||||
i = refs->add(id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
|
||||
{
|
||||
AutoMutex _l(mMutex);
|
||||
ssize_t i = refs->indexOfKey(id);
|
||||
LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
|
||||
if (i >= 0) {
|
||||
int32_t val = --(refs->editValueAt(i));
|
||||
if (val == 0) {
|
||||
refs->removeItemsAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printRefs(const KeyedVector<const void*, int32_t>& refs)
|
||||
{
|
||||
const size_t N=refs.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
mutable Mutex mMutex;
|
||||
KeyedVector<const void*, int32_t> mStrongRefs;
|
||||
KeyedVector<const void*, int32_t> mWeakRefs;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void RefBase::incStrong(const void* id) const
|
||||
{
|
||||
weakref_impl* const refs = mRefs;
|
||||
refs->addWeakRef(id);
|
||||
refs->incWeak(id);
|
||||
|
||||
refs->addStrongRef(id);
|
||||
const int32_t c = android_atomic_inc(&refs->mStrong);
|
||||
LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
|
||||
#if PRINT_REFS
|
||||
LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
|
||||
#endif
|
||||
if (c != INITIAL_STRONG_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
|
||||
const_cast<RefBase*>(this)->onFirstRef();
|
||||
}
|
||||
|
||||
void RefBase::decStrong(const void* id) const
|
||||
{
|
||||
weakref_impl* const refs = mRefs;
|
||||
refs->removeStrongRef(id);
|
||||
const int32_t c = android_atomic_dec(&refs->mStrong);
|
||||
#if PRINT_REFS
|
||||
LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
|
||||
#endif
|
||||
LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
|
||||
if (c == 1) {
|
||||
const_cast<RefBase*>(this)->onLastStrongRef(id);
|
||||
if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
refs->removeWeakRef(id);
|
||||
refs->decWeak(id);
|
||||
}
|
||||
|
||||
void RefBase::forceIncStrong(const void* id) const
|
||||
{
|
||||
weakref_impl* const refs = mRefs;
|
||||
refs->addWeakRef(id);
|
||||
refs->incWeak(id);
|
||||
|
||||
refs->addStrongRef(id);
|
||||
const int32_t c = android_atomic_inc(&refs->mStrong);
|
||||
LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
|
||||
refs);
|
||||
#if PRINT_REFS
|
||||
LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
|
||||
#endif
|
||||
|
||||
switch (c) {
|
||||
case INITIAL_STRONG_VALUE:
|
||||
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
|
||||
// fall through...
|
||||
case 0:
|
||||
const_cast<RefBase*>(this)->onFirstRef();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t RefBase::getStrongCount() const
|
||||
{
|
||||
return mRefs->mStrong;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RefBase* RefBase::weakref_type::refBase() const
|
||||
{
|
||||
return static_cast<const weakref_impl*>(this)->mBase;
|
||||
}
|
||||
|
||||
void RefBase::weakref_type::incWeak(const void* id)
|
||||
{
|
||||
weakref_impl* const impl = static_cast<weakref_impl*>(this);
|
||||
impl->addWeakRef(id);
|
||||
const int32_t c = android_atomic_inc(&impl->mWeak);
|
||||
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
|
||||
}
|
||||
|
||||
void RefBase::weakref_type::decWeak(const void* id)
|
||||
{
|
||||
weakref_impl* const impl = static_cast<weakref_impl*>(this);
|
||||
impl->removeWeakRef(id);
|
||||
const int32_t c = android_atomic_dec(&impl->mWeak);
|
||||
LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
|
||||
if (c != 1) return;
|
||||
|
||||
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
|
||||
if (impl->mStrong == INITIAL_STRONG_VALUE)
|
||||
delete impl->mBase;
|
||||
else {
|
||||
// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
|
||||
delete impl;
|
||||
}
|
||||
} else {
|
||||
impl->mBase->onLastWeakRef(id);
|
||||
if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
|
||||
delete impl->mBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RefBase::weakref_type::attemptIncStrong(const void* id)
|
||||
{
|
||||
incWeak(id);
|
||||
|
||||
weakref_impl* const impl = static_cast<weakref_impl*>(this);
|
||||
|
||||
int32_t curCount = impl->mStrong;
|
||||
LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
|
||||
this);
|
||||
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
|
||||
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
|
||||
break;
|
||||
}
|
||||
curCount = impl->mStrong;
|
||||
}
|
||||
|
||||
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
|
||||
bool allow;
|
||||
if (curCount == INITIAL_STRONG_VALUE) {
|
||||
// Attempting to acquire first strong reference... this is allowed
|
||||
// if the object does NOT have a longer lifetime (meaning the
|
||||
// implementation doesn't need to see this), or if the implementation
|
||||
// allows it to happen.
|
||||
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|
||||
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
|
||||
} else {
|
||||
// Attempting to revive the object... this is allowed
|
||||
// if the object DOES have a longer lifetime (so we can safely
|
||||
// call the object with only a weak ref) and the implementation
|
||||
// allows it to happen.
|
||||
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
|
||||
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
|
||||
}
|
||||
if (!allow) {
|
||||
decWeak(id);
|
||||
return false;
|
||||
}
|
||||
curCount = android_atomic_inc(&impl->mStrong);
|
||||
|
||||
// If the strong reference count has already been incremented by
|
||||
// someone else, the implementor of onIncStrongAttempted() is holding
|
||||
// an unneeded reference. So call onLastStrongRef() here to remove it.
|
||||
// (No, this is not pretty.) Note that we MUST NOT do this if we
|
||||
// are in fact acquiring the first reference.
|
||||
if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
|
||||
impl->mBase->onLastStrongRef(id);
|
||||
}
|
||||
}
|
||||
|
||||
impl->addWeakRef(id);
|
||||
impl->addStrongRef(id);
|
||||
|
||||
#if PRINT_REFS
|
||||
LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
|
||||
#endif
|
||||
|
||||
if (curCount == INITIAL_STRONG_VALUE) {
|
||||
android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
|
||||
impl->mBase->onFirstRef();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RefBase::weakref_type::attemptIncWeak(const void* id)
|
||||
{
|
||||
weakref_impl* const impl = static_cast<weakref_impl*>(this);
|
||||
|
||||
int32_t curCount = impl->mWeak;
|
||||
LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
|
||||
this);
|
||||
while (curCount > 0) {
|
||||
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
|
||||
break;
|
||||
}
|
||||
curCount = impl->mWeak;
|
||||
}
|
||||
|
||||
if (curCount > 0) {
|
||||
impl->addWeakRef(id);
|
||||
}
|
||||
|
||||
return curCount > 0;
|
||||
}
|
||||
|
||||
int32_t RefBase::weakref_type::getWeakCount() const
|
||||
{
|
||||
return static_cast<const weakref_impl*>(this)->mWeak;
|
||||
}
|
||||
|
||||
void RefBase::weakref_type::printRefs() const
|
||||
{
|
||||
static_cast<const weakref_impl*>(this)->printRefs();
|
||||
}
|
||||
|
||||
void RefBase::weakref_type::trackMe(bool enable, bool retain)
|
||||
{
|
||||
static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
|
||||
}
|
||||
|
||||
RefBase::weakref_type* RefBase::createWeak(const void* id) const
|
||||
{
|
||||
mRefs->incWeak(id);
|
||||
return mRefs;
|
||||
}
|
||||
|
||||
RefBase::weakref_type* RefBase::getWeakRefs() const
|
||||
{
|
||||
return mRefs;
|
||||
}
|
||||
|
||||
RefBase::RefBase()
|
||||
: mRefs(new weakref_impl(this))
|
||||
{
|
||||
// LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
|
||||
}
|
||||
|
||||
RefBase::~RefBase()
|
||||
{
|
||||
// LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
|
||||
if (mRefs->mWeak == 0) {
|
||||
// LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
|
||||
delete mRefs;
|
||||
}
|
||||
}
|
||||
|
||||
void RefBase::extendObjectLifetime(int32_t mode)
|
||||
{
|
||||
android_atomic_or(mode, &mRefs->mFlags);
|
||||
}
|
||||
|
||||
void RefBase::onFirstRef()
|
||||
{
|
||||
}
|
||||
|
||||
void RefBase::onLastStrongRef(const void* /*id*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
|
||||
{
|
||||
return (flags&FIRST_INC_STRONG) ? true : false;
|
||||
}
|
||||
|
||||
void RefBase::onLastWeakRef(const void* /*id*/)
|
||||
{
|
||||
}
|
||||
|
||||
}; // namespace android
|
3983
libs/utils/ResourceTypes.cpp
Normal file
3983
libs/utils/ResourceTypes.cpp
Normal file
File diff suppressed because it is too large
Load diff
113
libs/utils/SharedBuffer.cpp
Normal file
113
libs/utils/SharedBuffer.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utils/SharedBuffer.h>
|
||||
#include <utils/Atomic.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
SharedBuffer* SharedBuffer::alloc(size_t size)
|
||||
{
|
||||
SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
|
||||
if (sb) {
|
||||
sb->mRefs = 1;
|
||||
sb->mSize = size;
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
|
||||
{
|
||||
if (released->mRefs != 0) return -1; // XXX: invalid operation
|
||||
free(const_cast<SharedBuffer*>(released));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SharedBuffer* SharedBuffer::edit() const
|
||||
{
|
||||
if (onlyOwner()) {
|
||||
return const_cast<SharedBuffer*>(this);
|
||||
}
|
||||
SharedBuffer* sb = alloc(mSize);
|
||||
if (sb) {
|
||||
memcpy(sb->data(), data(), size());
|
||||
release();
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
SharedBuffer* SharedBuffer::editResize(size_t newSize) const
|
||||
{
|
||||
if (onlyOwner()) {
|
||||
SharedBuffer* buf = const_cast<SharedBuffer*>(this);
|
||||
if (buf->mSize == newSize) return buf;
|
||||
buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
|
||||
if (buf != NULL) {
|
||||
buf->mSize = newSize;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
SharedBuffer* sb = alloc(newSize);
|
||||
if (sb) {
|
||||
const size_t mySize = mSize;
|
||||
memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
|
||||
release();
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
SharedBuffer* SharedBuffer::attemptEdit() const
|
||||
{
|
||||
if (onlyOwner()) {
|
||||
return const_cast<SharedBuffer*>(this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SharedBuffer* SharedBuffer::reset(size_t new_size) const
|
||||
{
|
||||
// cheap-o-reset.
|
||||
SharedBuffer* sb = alloc(new_size);
|
||||
if (sb) {
|
||||
release();
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
void SharedBuffer::acquire() const {
|
||||
android_atomic_inc(&mRefs);
|
||||
}
|
||||
|
||||
int32_t SharedBuffer::release(uint32_t flags) const
|
||||
{
|
||||
int32_t prev = 1;
|
||||
if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
|
||||
mRefs = 0;
|
||||
if ((flags & eKeepStorage) == 0) {
|
||||
free(const_cast<SharedBuffer*>(this));
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
||||
}; // namespace android
|
388
libs/utils/Socket.cpp
Normal file
388
libs/utils/Socket.cpp
Normal file
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Internet address class.
|
||||
//
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
// This needs to come first, or Cygwin gets concerned about a potential
|
||||
// clash between WinSock and <sys/types.h>.
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <utils/Socket.h>
|
||||
#include <utils/inet_address.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
#ifndef HAVE_WINSOCK
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* Socket
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
# define INVALID_SOCKET (-1)
|
||||
#endif
|
||||
#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET)
|
||||
|
||||
/*static*/ bool Socket::mBootInitialized = false;
|
||||
|
||||
/*
|
||||
* Extract system-dependent error code.
|
||||
*/
|
||||
static inline int getSocketError(void) {
|
||||
#ifdef HAVE_WINSOCK
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* One-time initialization for socket code.
|
||||
*/
|
||||
/*static*/ bool Socket::bootInit(void)
|
||||
{
|
||||
#ifdef HAVE_WINSOCK
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
|
||||
err = WSAStartup(MAKEWORD(2, 0), &wsaData);
|
||||
if (err != 0) {
|
||||
LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
|
||||
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
|
||||
#endif
|
||||
|
||||
mBootInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* One-time shutdown for socket code.
|
||||
*/
|
||||
/*static*/ void Socket::finalShutdown(void)
|
||||
{
|
||||
#ifdef HAVE_WINSOCK
|
||||
WSACleanup();
|
||||
#endif
|
||||
mBootInitialized = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Simple constructor. Allow the application to create us and then make
|
||||
* bind/connect calls.
|
||||
*/
|
||||
Socket::Socket(void)
|
||||
: mSock(UNDEF_SOCKET)
|
||||
{
|
||||
if (!mBootInitialized)
|
||||
LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Destructor. Closes the socket and resets our storage.
|
||||
*/
|
||||
Socket::~Socket(void)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a socket and connect to the specified host and port.
|
||||
*/
|
||||
int Socket::connect(const char* host, int port)
|
||||
{
|
||||
if (mSock != UNDEF_SOCKET) {
|
||||
LOG(LOG_WARN, "socket", "Socket already connected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
InetSocketAddress sockAddr;
|
||||
if (!sockAddr.create(host, port))
|
||||
return -1;
|
||||
|
||||
//return doConnect(sockAddr);
|
||||
int foo;
|
||||
foo = doConnect(sockAddr);
|
||||
return foo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a socket and connect to the specified host and port.
|
||||
*/
|
||||
int Socket::connect(const InetAddress* addr, int port)
|
||||
{
|
||||
if (mSock != UNDEF_SOCKET) {
|
||||
LOG(LOG_WARN, "socket", "Socket already connected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
InetSocketAddress sockAddr;
|
||||
if (!sockAddr.create(addr, port))
|
||||
return -1;
|
||||
|
||||
return doConnect(sockAddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish creating a socket by connecting to the remote host.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int Socket::doConnect(const InetSocketAddress& sockAddr)
|
||||
{
|
||||
#ifdef HAVE_WINSOCK
|
||||
SOCKET sock;
|
||||
#else
|
||||
int sock;
|
||||
#endif
|
||||
const InetAddress* addr = sockAddr.getAddress();
|
||||
int port = sockAddr.getPort();
|
||||
struct sockaddr_in inaddr;
|
||||
DurationTimer connectTimer;
|
||||
|
||||
assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
|
||||
memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
|
||||
inaddr.sin_port = htons(port);
|
||||
|
||||
//fprintf(stderr, "--- connecting to %s:%d\n",
|
||||
// sockAddr.getHostName(), port);
|
||||
|
||||
sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
int err = getSocketError();
|
||||
LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
|
||||
return (err != 0) ? err : -1;
|
||||
}
|
||||
|
||||
connectTimer.start();
|
||||
|
||||
if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
|
||||
int err = getSocketError();
|
||||
LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
|
||||
sockAddr.getHostName(), port, err);
|
||||
return (err != 0) ? err : -1;
|
||||
}
|
||||
|
||||
connectTimer.stop();
|
||||
if ((long) connectTimer.durationUsecs() > 100000) {
|
||||
LOG(LOG_INFO, "socket",
|
||||
"Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
|
||||
port, ((long) connectTimer.durationUsecs()) / 1000000.0);
|
||||
}
|
||||
|
||||
mSock = (unsigned long) sock;
|
||||
LOG(LOG_VERBOSE, "socket",
|
||||
"--- connected to %s:%d\n", sockAddr.getHostName(), port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close the socket if it needs closing.
|
||||
*/
|
||||
bool Socket::close(void)
|
||||
{
|
||||
if (mSock != UNDEF_SOCKET) {
|
||||
//fprintf(stderr, "--- closing socket %lu\n", mSock);
|
||||
#ifdef HAVE_WINSOCK
|
||||
if (::closesocket((SOCKET) mSock) != 0)
|
||||
return false;
|
||||
#else
|
||||
if (::close((int) mSock) != 0)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
mSock = UNDEF_SOCKET;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read data from socket.
|
||||
*
|
||||
* Standard semantics: read up to "len" bytes into "buf". Returns the
|
||||
* number of bytes read, or less than zero on error.
|
||||
*/
|
||||
int Socket::read(void* buf, ssize_t len) const
|
||||
{
|
||||
if (mSock == UNDEF_SOCKET) {
|
||||
LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
|
||||
return -500;
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
SOCKET sock = (SOCKET) mSock;
|
||||
#else
|
||||
int sock = (int) mSock;
|
||||
#endif
|
||||
int cc;
|
||||
|
||||
cc = recv(sock, (char*)buf, len, 0);
|
||||
if (cc < 0) {
|
||||
int err = getSocketError();
|
||||
return (err > 0) ? -err : -1;
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data to a socket.
|
||||
*
|
||||
* Standard semantics: write up to "len" bytes into "buf". Returns the
|
||||
* number of bytes written, or less than zero on error.
|
||||
*/
|
||||
int Socket::write(const void* buf, ssize_t len) const
|
||||
{
|
||||
if (mSock == UNDEF_SOCKET) {
|
||||
LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
|
||||
return -500;
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
SOCKET sock = (SOCKET) mSock;
|
||||
#else
|
||||
int sock = (int) mSock;
|
||||
#endif
|
||||
int cc;
|
||||
|
||||
cc = send(sock, (const char*)buf, len, 0);
|
||||
if (cc < 0) {
|
||||
int err = getSocketError();
|
||||
return (err > 0) ? -err : -1;
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* Socket tests
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read all data from the socket. The data is read into a buffer that
|
||||
* expands as needed.
|
||||
*
|
||||
* On exit, the buffer is returned, and the length of the data is stored
|
||||
* in "*sz". A null byte is added to the end, but is not included in
|
||||
* the length.
|
||||
*/
|
||||
static char* socketReadAll(const Socket& s, int *sz)
|
||||
{
|
||||
int max, r;
|
||||
char *data, *ptr, *tmp;
|
||||
|
||||
data = (char*) malloc(max = 32768);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
ptr = data;
|
||||
|
||||
for (;;) {
|
||||
if ((ptr - data) == max) {
|
||||
tmp = (char*) realloc(data, max *= 2);
|
||||
if(tmp == 0) {
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
r = s.read(ptr, max - (ptr - data));
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r < 0) {
|
||||
LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
|
||||
break;
|
||||
}
|
||||
ptr += r;
|
||||
}
|
||||
|
||||
if ((ptr - data) == max) {
|
||||
tmp = (char*) realloc(data, max + 1);
|
||||
if (tmp == NULL) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
*ptr = '\0';
|
||||
*sz = (ptr - data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exercise the Socket class.
|
||||
*/
|
||||
void android::TestSockets(void)
|
||||
{
|
||||
printf("----- SOCKET TEST ------\n");
|
||||
Socket::bootInit();
|
||||
|
||||
char* buf = NULL;
|
||||
int len, cc;
|
||||
const char* kTestStr =
|
||||
"GET / HTTP/1.0\n"
|
||||
"Connection: close\n"
|
||||
"\n";
|
||||
|
||||
Socket sock;
|
||||
if (sock.connect("www.google.com", 80) != 0) {
|
||||
fprintf(stderr, "socket connected failed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
cc = sock.write(kTestStr, strlen(kTestStr));
|
||||
if (cc != (int) strlen(kTestStr)) {
|
||||
fprintf(stderr, "write failed, res=%d\n", cc);
|
||||
goto bail;
|
||||
}
|
||||
buf = socketReadAll(sock, &len);
|
||||
|
||||
printf("GOT '%s'\n", buf);
|
||||
|
||||
bail:
|
||||
sock.close();
|
||||
free(buf);
|
||||
}
|
||||
|
120
libs/utils/Static.cpp
Normal file
120
libs/utils/Static.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// All static variables go here, to control initialization and
|
||||
// destruction order in the library.
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <utils/BufferedTextOutput.h>
|
||||
#include <utils/IPCThreadState.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class LibUtilsFirstStatics
|
||||
{
|
||||
public:
|
||||
LibUtilsFirstStatics()
|
||||
{
|
||||
initialize_string8();
|
||||
initialize_string16();
|
||||
}
|
||||
|
||||
~LibUtilsFirstStatics()
|
||||
{
|
||||
terminate_string16();
|
||||
terminate_string8();
|
||||
}
|
||||
};
|
||||
|
||||
static LibUtilsFirstStatics gFirstStatics;
|
||||
int gDarwinCantLoadAllObjects = 1;
|
||||
|
||||
// ------------ Text output streams
|
||||
|
||||
Vector<int32_t> gTextBuffers;
|
||||
|
||||
class LogTextOutput : public BufferedTextOutput
|
||||
{
|
||||
public:
|
||||
LogTextOutput() : BufferedTextOutput(MULTITHREADED) { }
|
||||
virtual ~LogTextOutput() { };
|
||||
|
||||
protected:
|
||||
virtual status_t writeLines(const struct iovec& vec, size_t N)
|
||||
{
|
||||
android_writevLog(&vec, N);
|
||||
return NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
class FdTextOutput : public BufferedTextOutput
|
||||
{
|
||||
public:
|
||||
FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
|
||||
virtual ~FdTextOutput() { };
|
||||
|
||||
protected:
|
||||
virtual status_t writeLines(const struct iovec& vec, size_t N)
|
||||
{
|
||||
writev(mFD, &vec, N);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
private:
|
||||
int mFD;
|
||||
};
|
||||
|
||||
static LogTextOutput gLogTextOutput;
|
||||
static FdTextOutput gStdoutTextOutput(STDOUT_FILENO);
|
||||
static FdTextOutput gStderrTextOutput(STDERR_FILENO);
|
||||
|
||||
TextOutput& alog(gLogTextOutput);
|
||||
TextOutput& aout(gStdoutTextOutput);
|
||||
TextOutput& aerr(gStderrTextOutput);
|
||||
|
||||
#ifndef LIBUTILS_NATIVE
|
||||
|
||||
// ------------ ProcessState.cpp
|
||||
|
||||
Mutex gProcessMutex;
|
||||
sp<ProcessState> gProcess;
|
||||
|
||||
class LibUtilsIPCtStatics
|
||||
{
|
||||
public:
|
||||
LibUtilsIPCtStatics()
|
||||
{
|
||||
}
|
||||
|
||||
~LibUtilsIPCtStatics()
|
||||
{
|
||||
IPCThreadState::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
static LibUtilsIPCtStatics gIPCStatics;
|
||||
|
||||
// ------------ ServiceManager.cpp
|
||||
|
||||
Mutex gDefaultServiceManagerLock;
|
||||
sp<IServiceManager> gDefaultServiceManager;
|
||||
sp<IPermissionController> gPermissionController;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace android
|
79
libs/utils/StopWatch.cpp
Normal file
79
libs/utils/StopWatch.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "StopWatch"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/StopWatch.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
namespace android {
|
||||
|
||||
|
||||
StopWatch::StopWatch(const char *name, int clock, uint32_t flags)
|
||||
: mName(name), mClock(clock), mFlags(flags),
|
||||
mStartTime(0), mNumLaps(0)
|
||||
{
|
||||
mStartTime = systemTime(mClock);
|
||||
}
|
||||
|
||||
StopWatch::~StopWatch()
|
||||
{
|
||||
nsecs_t elapsed = elapsedTime();
|
||||
const int n = mNumLaps;
|
||||
LOGD("StopWatch %s (us): %lld ", mName, ns2us(elapsed));
|
||||
for (int i=0 ; i<n ; i++) {
|
||||
const nsecs_t soFar = mLaps[i].soFar;
|
||||
const nsecs_t thisLap = mLaps[i].thisLap;
|
||||
LOGD(" [%d: %lld, %lld]", i, ns2us(soFar), ns2us(thisLap));
|
||||
}
|
||||
}
|
||||
|
||||
const char* StopWatch::name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
nsecs_t StopWatch::lap()
|
||||
{
|
||||
nsecs_t elapsed = elapsedTime();
|
||||
if (mNumLaps >= 8) {
|
||||
elapsed = 0;
|
||||
} else {
|
||||
const int n = mNumLaps;
|
||||
mLaps[n].soFar = elapsed;
|
||||
mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed;
|
||||
mNumLaps = n+1;
|
||||
}
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
nsecs_t StopWatch::elapsedTime() const
|
||||
{
|
||||
return systemTime(mClock) - mStartTime;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
}; // namespace android
|
||||
|
609
libs/utils/String16.cpp
Normal file
609
libs/utils/String16.cpp
Normal file
|
@ -0,0 +1,609 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/String16.h>
|
||||
|
||||
#include <utils/Debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/TextOutput.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
# undef nhtol
|
||||
# undef htonl
|
||||
# undef nhtos
|
||||
# undef htons
|
||||
|
||||
# ifdef HAVE_LITTLE_ENDIAN
|
||||
# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
|
||||
# define htonl(x) ntohl(x)
|
||||
# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
|
||||
# define htons(x) ntohs(x)
|
||||
# else
|
||||
# define ntohl(x) (x)
|
||||
# define htonl(x) (x)
|
||||
# define ntohs(x) (x)
|
||||
# define htons(x) (x)
|
||||
# endif
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int strcmp16(const char16_t *s1, const char16_t *s2)
|
||||
{
|
||||
char16_t ch;
|
||||
int d = 0;
|
||||
|
||||
while ( 1 ) {
|
||||
d = (int)(ch = *s1++) - (int)*s2++;
|
||||
if ( d || !ch )
|
||||
break;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
|
||||
{
|
||||
char16_t ch;
|
||||
int d = 0;
|
||||
|
||||
while ( n-- ) {
|
||||
d = (int)(ch = *s1++) - (int)*s2++;
|
||||
if ( d || !ch )
|
||||
break;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
char16_t *strcpy16(char16_t *dst, const char16_t *src)
|
||||
{
|
||||
char16_t *q = dst;
|
||||
const char16_t *p = src;
|
||||
char16_t ch;
|
||||
|
||||
do {
|
||||
*q++ = ch = *p++;
|
||||
} while ( ch );
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t strlen16(const char16_t *s)
|
||||
{
|
||||
const char16_t *ss = s;
|
||||
while ( *ss )
|
||||
ss++;
|
||||
return ss-s;
|
||||
}
|
||||
|
||||
|
||||
char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
|
||||
{
|
||||
char16_t *q = dst;
|
||||
const char16_t *p = src;
|
||||
char ch;
|
||||
|
||||
while (n) {
|
||||
n--;
|
||||
*q++ = ch = *p++;
|
||||
if ( !ch )
|
||||
break;
|
||||
}
|
||||
|
||||
*q = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t strnlen16(const char16_t *s, size_t maxlen)
|
||||
{
|
||||
const char16_t *ss = s;
|
||||
|
||||
/* Important: the maxlen test must precede the reference through ss;
|
||||
since the byte beyond the maximum may segfault */
|
||||
while ((maxlen > 0) && *ss) {
|
||||
ss++;
|
||||
maxlen--;
|
||||
}
|
||||
return ss-s;
|
||||
}
|
||||
|
||||
int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
|
||||
{
|
||||
const char16_t* e1 = s1+n1;
|
||||
const char16_t* e2 = s2+n2;
|
||||
|
||||
while (s1 < e1 && s2 < e2) {
|
||||
const int d = (int)*s1++ - (int)*s2++;
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return n1 < n2
|
||||
? (0 - (int)*s2)
|
||||
: (n1 > n2
|
||||
? ((int)*s1 - 0)
|
||||
: 0);
|
||||
}
|
||||
|
||||
int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
|
||||
{
|
||||
const char16_t* e1 = s1H+n1;
|
||||
const char16_t* e2 = s2N+n2;
|
||||
|
||||
while (s1H < e1 && s2N < e2) {
|
||||
const char16_t c2 = ntohs(*s2N);
|
||||
const int d = (int)*s1H++ - (int)c2;
|
||||
s2N++;
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return n1 < n2
|
||||
? (0 - (int)ntohs(*s2N))
|
||||
: (n1 > n2
|
||||
? ((int)*s1H - 0)
|
||||
: 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
static inline size_t
|
||||
utf8_char_len(uint8_t ch)
|
||||
{
|
||||
return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
|
||||
}
|
||||
|
||||
#define UTF8_SHIFT_AND_MASK(unicode, byte) (unicode)<<=6; (unicode) |= (0x3f & (byte));
|
||||
|
||||
static inline uint32_t
|
||||
utf8_to_utf32(const uint8_t *src, size_t length)
|
||||
{
|
||||
uint32_t unicode;
|
||||
|
||||
switch (length)
|
||||
{
|
||||
case 1:
|
||||
return src[0];
|
||||
case 2:
|
||||
unicode = src[0] & 0x1f;
|
||||
UTF8_SHIFT_AND_MASK(unicode, src[1])
|
||||
return unicode;
|
||||
case 3:
|
||||
unicode = src[0] & 0x0f;
|
||||
UTF8_SHIFT_AND_MASK(unicode, src[1])
|
||||
UTF8_SHIFT_AND_MASK(unicode, src[2])
|
||||
return unicode;
|
||||
case 4:
|
||||
unicode = src[0] & 0x07;
|
||||
UTF8_SHIFT_AND_MASK(unicode, src[1])
|
||||
UTF8_SHIFT_AND_MASK(unicode, src[2])
|
||||
UTF8_SHIFT_AND_MASK(unicode, src[3])
|
||||
return unicode;
|
||||
default:
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
//printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static SharedBuffer* gEmptyStringBuf = NULL;
|
||||
static char16_t* gEmptyString = NULL;
|
||||
|
||||
static inline char16_t* getEmptyString()
|
||||
{
|
||||
gEmptyStringBuf->acquire();
|
||||
return gEmptyString;
|
||||
}
|
||||
|
||||
void initialize_string16()
|
||||
{
|
||||
SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
*str = 0;
|
||||
gEmptyStringBuf = buf;
|
||||
gEmptyString = str;
|
||||
}
|
||||
|
||||
void terminate_string16()
|
||||
{
|
||||
SharedBuffer::bufferFromData(gEmptyString)->release();
|
||||
gEmptyStringBuf = NULL;
|
||||
gEmptyString = NULL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Note: not dealing with generating surrogate pairs.
|
||||
static char16_t* allocFromUTF8(const char* in, size_t len)
|
||||
{
|
||||
if (len == 0) return getEmptyString();
|
||||
|
||||
size_t chars = 0;
|
||||
const char* end = in+len;
|
||||
const char* p = in;
|
||||
|
||||
while (p < end) {
|
||||
chars++;
|
||||
p += utf8_char_len(*p);
|
||||
}
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
|
||||
if (buf) {
|
||||
p = in;
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
char16_t* d = str;
|
||||
while (p < end) {
|
||||
size_t len = utf8_char_len(*p);
|
||||
*d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len);
|
||||
p += len;
|
||||
}
|
||||
*d = 0;
|
||||
|
||||
//printf("Created UTF-16 string from UTF-8 \"%s\":", in);
|
||||
//printHexData(1, str, buf->size(), 16, 1);
|
||||
//printf("\n");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
return getEmptyString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
String16::String16()
|
||||
: mString(getEmptyString())
|
||||
{
|
||||
}
|
||||
|
||||
String16::String16(const String16& o)
|
||||
: mString(o.mString)
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->acquire();
|
||||
}
|
||||
|
||||
String16::String16(const String16& o, size_t len, size_t begin)
|
||||
: mString(getEmptyString())
|
||||
{
|
||||
setTo(o, len, begin);
|
||||
}
|
||||
|
||||
String16::String16(const char16_t* o)
|
||||
{
|
||||
size_t len = strlen16(o);
|
||||
SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
|
||||
LOG_ASSERT(buf, "Unable to allocate shared buffer");
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
strcpy16(str, o);
|
||||
mString = str;
|
||||
return;
|
||||
}
|
||||
|
||||
mString = getEmptyString();
|
||||
}
|
||||
|
||||
String16::String16(const char16_t* o, size_t len)
|
||||
{
|
||||
SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
|
||||
LOG_ASSERT(buf, "Unable to allocate shared buffer");
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
memcpy(str, o, len*sizeof(char16_t));
|
||||
str[len] = 0;
|
||||
mString = str;
|
||||
return;
|
||||
}
|
||||
|
||||
mString = getEmptyString();
|
||||
}
|
||||
|
||||
String16::String16(const String8& o)
|
||||
: mString(allocFromUTF8(o.string(), o.size()))
|
||||
{
|
||||
}
|
||||
|
||||
String16::String16(const char* o)
|
||||
: mString(allocFromUTF8(o, strlen(o)))
|
||||
{
|
||||
}
|
||||
|
||||
String16::String16(const char* o, size_t len)
|
||||
: mString(allocFromUTF8(o, len))
|
||||
{
|
||||
}
|
||||
|
||||
String16::~String16()
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
}
|
||||
|
||||
void String16::setTo(const String16& other)
|
||||
{
|
||||
SharedBuffer::bufferFromData(other.mString)->acquire();
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = other.mString;
|
||||
}
|
||||
|
||||
status_t String16::setTo(const String16& other, size_t len, size_t begin)
|
||||
{
|
||||
const size_t N = other.size();
|
||||
if (begin >= N) {
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = getEmptyString();
|
||||
return NO_ERROR;
|
||||
}
|
||||
if ((begin+len) > N) len = N-begin;
|
||||
if (begin == 0 && len == N) {
|
||||
setTo(other);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
if (&other == this) {
|
||||
LOG_ALWAYS_FATAL("Not implemented");
|
||||
}
|
||||
|
||||
return setTo(other.string()+begin, len);
|
||||
}
|
||||
|
||||
status_t String16::setTo(const char16_t* other)
|
||||
{
|
||||
return setTo(other, strlen16(other));
|
||||
}
|
||||
|
||||
status_t String16::setTo(const char16_t* other, size_t len)
|
||||
{
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize((len+1)*sizeof(char16_t));
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
memcpy(str, other, len*sizeof(char16_t));
|
||||
str[len] = 0;
|
||||
mString = str;
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t String16::append(const String16& other)
|
||||
{
|
||||
const size_t myLen = size();
|
||||
const size_t otherLen = other.size();
|
||||
if (myLen == 0) {
|
||||
setTo(other);
|
||||
return NO_ERROR;
|
||||
} else if (otherLen == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize((myLen+otherLen+1)*sizeof(char16_t));
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
|
||||
mString = str;
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t String16::append(const char16_t* chrs, size_t otherLen)
|
||||
{
|
||||
const size_t myLen = size();
|
||||
if (myLen == 0) {
|
||||
setTo(chrs, otherLen);
|
||||
return NO_ERROR;
|
||||
} else if (otherLen == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize((myLen+otherLen+1)*sizeof(char16_t));
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
|
||||
str[myLen+otherLen] = 0;
|
||||
mString = str;
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t String16::insert(size_t pos, const char16_t* chrs)
|
||||
{
|
||||
return insert(pos, chrs, strlen16(chrs));
|
||||
}
|
||||
|
||||
status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
|
||||
{
|
||||
const size_t myLen = size();
|
||||
if (myLen == 0) {
|
||||
return setTo(chrs, len);
|
||||
return NO_ERROR;
|
||||
} else if (len == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
if (pos > myLen) pos = myLen;
|
||||
|
||||
#if 0
|
||||
printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
|
||||
String8(*this).string(), pos,
|
||||
len, myLen, String8(chrs, len).string());
|
||||
#endif
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize((myLen+len+1)*sizeof(char16_t));
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
if (pos < myLen) {
|
||||
memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
|
||||
}
|
||||
memcpy(str+pos, chrs, len*sizeof(char16_t));
|
||||
str[myLen+len] = 0;
|
||||
mString = str;
|
||||
#if 0
|
||||
printf("Result (%d chrs): %s\n", size(), String8(*this).string());
|
||||
#endif
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
ssize_t String16::findFirst(char16_t c) const
|
||||
{
|
||||
const char16_t* str = string();
|
||||
const char16_t* p = str;
|
||||
const char16_t* e = p + size();
|
||||
while (p < e) {
|
||||
if (*p == c) {
|
||||
return p-str;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t String16::findLast(char16_t c) const
|
||||
{
|
||||
const char16_t* str = string();
|
||||
const char16_t* p = str;
|
||||
const char16_t* e = p + size();
|
||||
while (p < e) {
|
||||
e--;
|
||||
if (*e == c) {
|
||||
return e-str;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool String16::startsWith(const String16& prefix) const
|
||||
{
|
||||
const size_t ps = prefix.size();
|
||||
if (ps > size()) return false;
|
||||
return strzcmp16(mString, ps, prefix.string(), ps) == 0;
|
||||
}
|
||||
|
||||
bool String16::startsWith(const char16_t* prefix) const
|
||||
{
|
||||
const size_t ps = strlen16(prefix);
|
||||
if (ps > size()) return false;
|
||||
return strncmp16(mString, prefix, ps) == 0;
|
||||
}
|
||||
|
||||
status_t String16::makeLower()
|
||||
{
|
||||
const size_t N = size();
|
||||
const char16_t* str = string();
|
||||
char16_t* edit = NULL;
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const char16_t v = str[i];
|
||||
if (v >= 'A' && v <= 'Z') {
|
||||
if (!edit) {
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
|
||||
if (!buf) {
|
||||
return NO_MEMORY;
|
||||
}
|
||||
edit = (char16_t*)buf->data();
|
||||
mString = str = edit;
|
||||
}
|
||||
edit[i] = tolower((char)v);
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
|
||||
{
|
||||
const size_t N = size();
|
||||
const char16_t* str = string();
|
||||
char16_t* edit = NULL;
|
||||
for (size_t i=0; i<N; i++) {
|
||||
if (str[i] == replaceThis) {
|
||||
if (!edit) {
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
|
||||
if (!buf) {
|
||||
return NO_MEMORY;
|
||||
}
|
||||
edit = (char16_t*)buf->data();
|
||||
mString = str = edit;
|
||||
}
|
||||
edit[i] = withThis;
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t String16::remove(size_t len, size_t begin)
|
||||
{
|
||||
const size_t N = size();
|
||||
if (begin >= N) {
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = getEmptyString();
|
||||
return NO_ERROR;
|
||||
}
|
||||
if ((begin+len) > N) len = N-begin;
|
||||
if (begin == 0 && len == N) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
if (begin > 0) {
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize((N+1)*sizeof(char16_t));
|
||||
if (!buf) {
|
||||
return NO_MEMORY;
|
||||
}
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
|
||||
mString = str;
|
||||
}
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize((len+1)*sizeof(char16_t));
|
||||
if (buf) {
|
||||
char16_t* str = (char16_t*)buf->data();
|
||||
str[len] = 0;
|
||||
mString = str;
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const String16& val)
|
||||
{
|
||||
to << String8(val).string();
|
||||
return to;
|
||||
}
|
||||
|
||||
}; // namespace android
|
604
libs/utils/String8.cpp
Normal file
604
libs/utils/String8.cpp
Normal file
|
@ -0,0 +1,604 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/TextOutput.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <private/utils/Static.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static const uint32_t kByteMask = 0x000000BF;
|
||||
static const uint32_t kByteMark = 0x00000080;
|
||||
|
||||
// Surrogates aren't valid for UTF-32 characters, so define some
|
||||
// constants that will let us screen them out.
|
||||
static const uint32_t kUnicodeSurrogateHighStart = 0x0000D800;
|
||||
static const uint32_t kUnicodeSurrogateHighEnd = 0x0000DBFF;
|
||||
static const uint32_t kUnicodeSurrogateLowStart = 0x0000DC00;
|
||||
static const uint32_t kUnicodeSurrogateLowEnd = 0x0000DFFF;
|
||||
static const uint32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart;
|
||||
static const uint32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd;
|
||||
|
||||
// Mask used to set appropriate bits in first byte of UTF-8 sequence,
|
||||
// indexed by number of bytes in the sequence.
|
||||
static const uint32_t kFirstByteMark[] = {
|
||||
0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
|
||||
};
|
||||
|
||||
// Separator used by resource paths. This is not platform dependent contrary
|
||||
// to OS_PATH_SEPARATOR.
|
||||
#define RES_PATH_SEPARATOR '/'
|
||||
|
||||
// Return number of utf8 bytes required for the character.
|
||||
static size_t utf32_to_utf8_bytes(uint32_t srcChar)
|
||||
{
|
||||
size_t bytesToWrite;
|
||||
|
||||
// Figure out how many bytes the result will require.
|
||||
if (srcChar < 0x00000080)
|
||||
{
|
||||
bytesToWrite = 1;
|
||||
}
|
||||
else if (srcChar < 0x00000800)
|
||||
{
|
||||
bytesToWrite = 2;
|
||||
}
|
||||
else if (srcChar < 0x00010000)
|
||||
{
|
||||
if ((srcChar < kUnicodeSurrogateStart)
|
||||
|| (srcChar > kUnicodeSurrogateEnd))
|
||||
{
|
||||
bytesToWrite = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Surrogates are invalid UTF-32 characters.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Max code point for Unicode is 0x0010FFFF.
|
||||
else if (srcChar < 0x00110000)
|
||||
{
|
||||
bytesToWrite = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid UTF-32 character.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bytesToWrite;
|
||||
}
|
||||
|
||||
// Write out the source character to <dstP>.
|
||||
|
||||
static void utf32_to_utf8(uint8_t* dstP, uint32_t srcChar, size_t bytes)
|
||||
{
|
||||
dstP += bytes;
|
||||
switch (bytes)
|
||||
{ /* note: everything falls through. */
|
||||
case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
|
||||
case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
|
||||
case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
|
||||
case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static SharedBuffer* gEmptyStringBuf = NULL;
|
||||
static char* gEmptyString = NULL;
|
||||
|
||||
extern int gDarwinCantLoadAllObjects;
|
||||
int gDarwinIsReallyAnnoying;
|
||||
|
||||
static inline char* getEmptyString()
|
||||
{
|
||||
gEmptyStringBuf->acquire();
|
||||
return gEmptyString;
|
||||
}
|
||||
|
||||
void initialize_string8()
|
||||
{
|
||||
#ifdef LIBUTILS_NATIVE
|
||||
// Bite me, Darwin!
|
||||
gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
|
||||
#endif
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::alloc(1);
|
||||
char* str = (char*)buf->data();
|
||||
*str = 0;
|
||||
gEmptyStringBuf = buf;
|
||||
gEmptyString = str;
|
||||
}
|
||||
|
||||
void terminate_string8()
|
||||
{
|
||||
SharedBuffer::bufferFromData(gEmptyString)->release();
|
||||
gEmptyStringBuf = NULL;
|
||||
gEmptyString = NULL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static char* allocFromUTF8(const char* in, size_t len)
|
||||
{
|
||||
if (len > 0) {
|
||||
SharedBuffer* buf = SharedBuffer::alloc(len+1);
|
||||
LOG_ASSERT(buf, "Unable to allocate shared buffer");
|
||||
if (buf) {
|
||||
char* str = (char*)buf->data();
|
||||
memcpy(str, in, len);
|
||||
str[len] = 0;
|
||||
return str;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return getEmptyString();
|
||||
}
|
||||
|
||||
// Note: not dealing with expanding surrogate pairs.
|
||||
static char* allocFromUTF16(const char16_t* in, size_t len)
|
||||
{
|
||||
if (len == 0) return getEmptyString();
|
||||
|
||||
size_t bytes = 0;
|
||||
const char16_t* end = in+len;
|
||||
const char16_t* p = in;
|
||||
|
||||
while (p < end) {
|
||||
bytes += utf32_to_utf8_bytes(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
|
||||
LOG_ASSERT(buf, "Unable to allocate shared buffer");
|
||||
if (buf) {
|
||||
p = in;
|
||||
char* str = (char*)buf->data();
|
||||
char* d = str;
|
||||
while (p < end) {
|
||||
uint32_t c = *p++;
|
||||
size_t len = utf32_to_utf8_bytes(c);
|
||||
utf32_to_utf8((uint8_t*)d, c, len);
|
||||
d += len;
|
||||
}
|
||||
*d = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
return getEmptyString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
String8::String8()
|
||||
: mString(getEmptyString())
|
||||
{
|
||||
}
|
||||
|
||||
String8::String8(const String8& o)
|
||||
: mString(o.mString)
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->acquire();
|
||||
}
|
||||
|
||||
String8::String8(const char* o)
|
||||
: mString(allocFromUTF8(o, strlen(o)))
|
||||
{
|
||||
if (mString == NULL) {
|
||||
mString = getEmptyString();
|
||||
}
|
||||
}
|
||||
|
||||
String8::String8(const char* o, size_t len)
|
||||
: mString(allocFromUTF8(o, len))
|
||||
{
|
||||
if (mString == NULL) {
|
||||
mString = getEmptyString();
|
||||
}
|
||||
}
|
||||
|
||||
String8::String8(const String16& o)
|
||||
: mString(allocFromUTF16(o.string(), o.size()))
|
||||
{
|
||||
}
|
||||
|
||||
String8::String8(const char16_t* o)
|
||||
: mString(allocFromUTF16(o, strlen16(o)))
|
||||
{
|
||||
}
|
||||
|
||||
String8::String8(const char16_t* o, size_t len)
|
||||
: mString(allocFromUTF16(o, len))
|
||||
{
|
||||
}
|
||||
|
||||
String8::~String8()
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
}
|
||||
|
||||
void String8::setTo(const String8& other)
|
||||
{
|
||||
SharedBuffer::bufferFromData(other.mString)->acquire();
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = other.mString;
|
||||
}
|
||||
|
||||
status_t String8::setTo(const char* other)
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = allocFromUTF8(other, strlen(other));
|
||||
if (mString) return NO_ERROR;
|
||||
|
||||
mString = getEmptyString();
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t String8::setTo(const char* other, size_t len)
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = allocFromUTF8(other, len);
|
||||
if (mString) return NO_ERROR;
|
||||
|
||||
mString = getEmptyString();
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t String8::setTo(const char16_t* other, size_t len)
|
||||
{
|
||||
SharedBuffer::bufferFromData(mString)->release();
|
||||
mString = allocFromUTF16(other, len);
|
||||
if (mString) return NO_ERROR;
|
||||
|
||||
mString = getEmptyString();
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t String8::append(const String8& other)
|
||||
{
|
||||
const size_t otherLen = other.bytes();
|
||||
if (bytes() == 0) {
|
||||
setTo(other);
|
||||
return NO_ERROR;
|
||||
} else if (otherLen == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
return real_append(other.string(), otherLen);
|
||||
}
|
||||
|
||||
status_t String8::append(const char* other)
|
||||
{
|
||||
return append(other, strlen(other));
|
||||
}
|
||||
|
||||
status_t String8::append(const char* other, size_t otherLen)
|
||||
{
|
||||
if (bytes() == 0) {
|
||||
return setTo(other, otherLen);
|
||||
} else if (otherLen == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
return real_append(other, otherLen);
|
||||
}
|
||||
|
||||
status_t String8::real_append(const char* other, size_t otherLen)
|
||||
{
|
||||
const size_t myLen = bytes();
|
||||
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize(myLen+otherLen+1);
|
||||
if (buf) {
|
||||
char* str = (char*)buf->data();
|
||||
mString = str;
|
||||
str += myLen;
|
||||
memcpy(str, other, otherLen);
|
||||
str[otherLen] = '\0';
|
||||
return NO_ERROR;
|
||||
}
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
char* String8::lockBuffer(size_t size)
|
||||
{
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize(size+1);
|
||||
if (buf) {
|
||||
char* str = (char*)buf->data();
|
||||
mString = str;
|
||||
return str;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void String8::unlockBuffer()
|
||||
{
|
||||
unlockBuffer(strlen(mString));
|
||||
}
|
||||
|
||||
status_t String8::unlockBuffer(size_t size)
|
||||
{
|
||||
if (size != this->size()) {
|
||||
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
|
||||
->editResize(size+1);
|
||||
if (buf) {
|
||||
char* str = (char*)buf->data();
|
||||
str[size] = 0;
|
||||
mString = str;
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
ssize_t String8::find(const char* other, size_t start) const
|
||||
{
|
||||
size_t len = size();
|
||||
if (start >= len) {
|
||||
return -1;
|
||||
}
|
||||
const char* s = mString+start;
|
||||
const char* p = strstr(s, other);
|
||||
return p ? p-mString : -1;
|
||||
}
|
||||
|
||||
void String8::toLower()
|
||||
{
|
||||
toLower(0, size());
|
||||
}
|
||||
|
||||
void String8::toLower(size_t start, size_t length)
|
||||
{
|
||||
const size_t len = size();
|
||||
if (start >= len) {
|
||||
return;
|
||||
}
|
||||
if (start+length > len) {
|
||||
length = len-start;
|
||||
}
|
||||
char* buf = lockBuffer(len);
|
||||
buf += start;
|
||||
while (length > 0) {
|
||||
*buf = tolower(*buf);
|
||||
buf++;
|
||||
length--;
|
||||
}
|
||||
unlockBuffer(len);
|
||||
}
|
||||
|
||||
void String8::toUpper()
|
||||
{
|
||||
toUpper(0, size());
|
||||
}
|
||||
|
||||
void String8::toUpper(size_t start, size_t length)
|
||||
{
|
||||
const size_t len = size();
|
||||
if (start >= len) {
|
||||
return;
|
||||
}
|
||||
if (start+length > len) {
|
||||
length = len-start;
|
||||
}
|
||||
char* buf = lockBuffer(len);
|
||||
buf += start;
|
||||
while (length > 0) {
|
||||
*buf = toupper(*buf);
|
||||
buf++;
|
||||
length--;
|
||||
}
|
||||
unlockBuffer(len);
|
||||
}
|
||||
|
||||
TextOutput& operator<<(TextOutput& to, const String8& val)
|
||||
{
|
||||
to << val.string();
|
||||
return to;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Path functions
|
||||
|
||||
|
||||
void String8::setPathName(const char* name)
|
||||
{
|
||||
setPathName(name, strlen(name));
|
||||
}
|
||||
|
||||
void String8::setPathName(const char* name, size_t len)
|
||||
{
|
||||
char* buf = lockBuffer(len);
|
||||
|
||||
memcpy(buf, name, len);
|
||||
|
||||
// remove trailing path separator, if present
|
||||
if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
|
||||
len--;
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
unlockBuffer(len);
|
||||
}
|
||||
|
||||
String8 String8::getPathLeaf(void) const
|
||||
{
|
||||
const char* cp;
|
||||
const char*const buf = mString;
|
||||
|
||||
cp = strrchr(buf, OS_PATH_SEPARATOR);
|
||||
if (cp == NULL)
|
||||
return String8(*this);
|
||||
else
|
||||
return String8(cp+1);
|
||||
}
|
||||
|
||||
String8 String8::getPathDir(void) const
|
||||
{
|
||||
const char* cp;
|
||||
const char*const str = mString;
|
||||
|
||||
cp = strrchr(str, OS_PATH_SEPARATOR);
|
||||
if (cp == NULL)
|
||||
return String8("");
|
||||
else
|
||||
return String8(str, cp - str);
|
||||
}
|
||||
|
||||
String8 String8::walkPath(String8* outRemains) const
|
||||
{
|
||||
const char* cp;
|
||||
const char*const str = mString;
|
||||
const char* buf = str;
|
||||
|
||||
cp = strchr(buf, OS_PATH_SEPARATOR);
|
||||
if (cp == buf) {
|
||||
// don't include a leading '/'.
|
||||
buf = buf+1;
|
||||
cp = strchr(buf, OS_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
if (cp == NULL) {
|
||||
String8 res = buf != str ? String8(buf) : *this;
|
||||
if (outRemains) *outRemains = String8("");
|
||||
return res;
|
||||
}
|
||||
|
||||
String8 res(buf, cp-buf);
|
||||
if (outRemains) *outRemains = String8(cp+1);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for finding the start of an extension in a pathname.
|
||||
*
|
||||
* Returns a pointer inside mString, or NULL if no extension was found.
|
||||
*/
|
||||
char* String8::find_extension(void) const
|
||||
{
|
||||
const char* lastSlash;
|
||||
const char* lastDot;
|
||||
int extLen;
|
||||
const char* const str = mString;
|
||||
|
||||
// only look at the filename
|
||||
lastSlash = strrchr(str, OS_PATH_SEPARATOR);
|
||||
if (lastSlash == NULL)
|
||||
lastSlash = str;
|
||||
else
|
||||
lastSlash++;
|
||||
|
||||
// find the last dot
|
||||
lastDot = strrchr(lastSlash, '.');
|
||||
if (lastDot == NULL)
|
||||
return NULL;
|
||||
|
||||
// looks good, ship it
|
||||
return const_cast<char*>(lastDot);
|
||||
}
|
||||
|
||||
String8 String8::getPathExtension(void) const
|
||||
{
|
||||
char* ext;
|
||||
|
||||
ext = find_extension();
|
||||
if (ext != NULL)
|
||||
return String8(ext);
|
||||
else
|
||||
return String8("");
|
||||
}
|
||||
|
||||
String8 String8::getBasePath(void) const
|
||||
{
|
||||
char* ext;
|
||||
const char* const str = mString;
|
||||
|
||||
ext = find_extension();
|
||||
if (ext == NULL)
|
||||
return String8(*this);
|
||||
else
|
||||
return String8(str, ext - str);
|
||||
}
|
||||
|
||||
String8& String8::appendPath(const char* name)
|
||||
{
|
||||
// TODO: The test below will fail for Win32 paths. Fix later or ignore.
|
||||
if (name[0] != OS_PATH_SEPARATOR) {
|
||||
if (*name == '\0') {
|
||||
// nothing to do
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t len = length();
|
||||
if (len == 0) {
|
||||
// no existing filename, just use the new one
|
||||
setPathName(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// make room for oldPath + '/' + newPath
|
||||
int newlen = strlen(name);
|
||||
|
||||
char* buf = lockBuffer(len+1+newlen);
|
||||
|
||||
// insert a '/' if needed
|
||||
if (buf[len-1] != OS_PATH_SEPARATOR)
|
||||
buf[len++] = OS_PATH_SEPARATOR;
|
||||
|
||||
memcpy(buf+len, name, newlen+1);
|
||||
len += newlen;
|
||||
|
||||
unlockBuffer(len);
|
||||
|
||||
return *this;
|
||||
} else {
|
||||
setPathName(name);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
String8& String8::convertToResPath()
|
||||
{
|
||||
#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
|
||||
size_t len = length();
|
||||
if (len > 0) {
|
||||
char * buf = lockBuffer(len);
|
||||
for (char * end = buf + len; buf < end; ++buf) {
|
||||
if (*buf == OS_PATH_SEPARATOR)
|
||||
*buf = RES_PATH_SEPARATOR;
|
||||
}
|
||||
unlockBuffer(len);
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
}; // namespace android
|
139
libs/utils/SystemClock.cpp
Normal file
139
libs/utils/SystemClock.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* System clock functions.
|
||||
*/
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <utils/Atomic.h>
|
||||
#include <linux/android_alarm.h>
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utils/SystemClock.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
#define LOG_TAG "SystemClock"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Set the current time. This only works when running as root.
|
||||
*/
|
||||
int setCurrentTimeMillis(int64_t millis)
|
||||
{
|
||||
#if WIN32
|
||||
// not implemented
|
||||
return -1;
|
||||
#else
|
||||
struct timeval tv;
|
||||
#if HAVE_ANDROID_OS
|
||||
struct timespec ts;
|
||||
int fd;
|
||||
int res;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
if (millis <= 0 || millis / 1000LL >= INT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tv.tv_sec = (time_t) (millis / 1000LL);
|
||||
tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
|
||||
|
||||
LOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
|
||||
|
||||
#if HAVE_ANDROID_OS
|
||||
fd = open("/dev/alarm", O_RDWR);
|
||||
if(fd < 0) {
|
||||
LOGW("Unable to open alarm driver: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
|
||||
if(res < 0) {
|
||||
LOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
close(fd);
|
||||
#else
|
||||
if (settimeofday(&tv, NULL) != 0) {
|
||||
LOGW("Unable to set clock to %d.%d: %s\n",
|
||||
(int) tv.tv_sec, (int) tv.tv_usec, strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
/*
|
||||
* native public static long uptimeMillis();
|
||||
*/
|
||||
int64_t uptimeMillis()
|
||||
{
|
||||
int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
return (int64_t) nanoseconds_to_milliseconds(when);
|
||||
}
|
||||
|
||||
/*
|
||||
* native public static long elapsedRealtime();
|
||||
*/
|
||||
int64_t elapsedRealtime()
|
||||
{
|
||||
#if HAVE_ANDROID_OS
|
||||
static int s_fd = -1;
|
||||
|
||||
if (s_fd == -1) {
|
||||
int fd = open("/dev/alarm", O_RDONLY);
|
||||
if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
struct timespec ts;
|
||||
int result = ioctl(s_fd,
|
||||
ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
|
||||
|
||||
if (result == 0) {
|
||||
int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
|
||||
return (int64_t) nanoseconds_to_milliseconds(when);
|
||||
} else {
|
||||
// XXX: there was an error, probably because the driver didn't
|
||||
// exist ... this should return
|
||||
// a real error, like an exception!
|
||||
int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
return (int64_t) nanoseconds_to_milliseconds(when);
|
||||
}
|
||||
#else
|
||||
int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
return (int64_t) nanoseconds_to_milliseconds(when);
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // namespace android
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue