summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:08:08 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:08:08 -0800
commit35237d135807af84bf9b0e5b8d7f8633e58db6f5 (patch)
treed8bcf3ada2182d248604728285dd80abb466f22a
parent4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53 (diff)
downloadsystem_core-35237d135807af84bf9b0e5b8d7f8633e58db6f5.tar.gz
system_core-35237d135807af84bf9b0e5b8d7f8633e58db6f5.tar.bz2
system_core-35237d135807af84bf9b0e5b8d7f8633e58db6f5.zip
Code drop from //branches/cupcake/...@124589
-rw-r--r--Android.mk3
-rw-r--r--adb/Android.mk48
-rw-r--r--adb/OVERVIEW.TXT139
-rw-r--r--adb/SERVICES.TXT245
-rw-r--r--adb/adb.c108
-rw-r--r--adb/adb.h23
-rw-r--r--adb/adb_client.c26
-rw-r--r--adb/commandline.c56
-rw-r--r--adb/file_sync_client.c26
-rw-r--r--adb/file_sync_service.c6
-rw-r--r--adb/framebuffer_service.c9
-rw-r--r--adb/get_my_path_windows.c12
-rw-r--r--adb/jdwp_service.c4
-rw-r--r--adb/sockets.c162
-rw-r--r--adb/sysdeps_win32.c116
-rw-r--r--adb/transport_local.c15
-rw-r--r--adb/transport_usb.c12
-rw-r--r--adb/usb_linux_client.c2
-rw-r--r--adb/usb_osx.c22
-rw-r--r--adb/usb_windows.c18
-rw-r--r--adb/utils.c106
-rw-r--r--adb/utils.h68
-rw-r--r--cpio/Android.mk2
-rw-r--r--debuggerd/Android.mk4
-rw-r--r--debuggerd/unwind-arm.c50
-rw-r--r--debuggerd/utility.c7
-rw-r--r--debuggerd/utility.h2
-rw-r--r--fastboot/Android.mk2
-rw-r--r--fastboot/fastboot.c15
-rw-r--r--include/arch/linux-arm/AndroidConfig.h6
-rw-r--r--include/arch/target_linux-x86/AndroidConfig.h296
-rw-r--r--include/cutils/tztime.h15
-rw-r--r--include/pixelflinger/format.h5
-rw-r--r--include/private/android_filesystem_config.h4
-rw-r--r--include/private/pixelflinger/ggl_context.h10
-rw-r--r--init/README.BOOTCHART44
-rw-r--r--init/bootchart.c73
-rw-r--r--init/bootchart.h36
-rw-r--r--init/builtins.c46
-rw-r--r--init/devices.c21
-rwxr-xr-xinit/grab-bootchart.sh4
-rw-r--r--init/init.c21
-rw-r--r--init/keywords.h2
-rw-r--r--init/parser.c1
-rw-r--r--init/property_service.c2
-rw-r--r--init/readme.txt3
-rw-r--r--libcutils/Android.mk11
-rw-r--r--libcutils/atomic-android-arm.S52
-rw-r--r--libcutils/tzstrftime.c834
-rw-r--r--libnetutils/dhcp_utils.c16
-rw-r--r--libpixelflinger/Android.mk3
-rw-r--r--libpixelflinger/codeflinger/GGLAssembler.cpp63
-rw-r--r--libpixelflinger/codeflinger/GGLAssembler.h5
-rw-r--r--libpixelflinger/codeflinger/blending.cpp6
-rw-r--r--libpixelflinger/codeflinger/load_store.cpp2
-rw-r--r--libpixelflinger/codeflinger/texturing.cpp43
-rw-r--r--libpixelflinger/format.cpp4
-rw-r--r--libpixelflinger/scanline.cpp15
-rw-r--r--libpixelflinger/tests/Android.mk1
-rw-r--r--libpixelflinger/tests/codegen/Android.mk15
-rw-r--r--libpixelflinger/tests/codegen/codegen.cpp21
-rw-r--r--logcat/event-log-tags20
-rw-r--r--logwrapper/logwrapper.c99
-rw-r--r--mkbootimg/Android.mk2
-rw-r--r--mountd/ASEC.c770
-rw-r--r--mountd/ASEC.h66
-rw-r--r--mountd/Android.mk3
-rw-r--r--mountd/AutoMount.c210
-rw-r--r--mountd/ProcessKiller.c19
-rw-r--r--mountd/Server.c81
-rw-r--r--mountd/dm-ioctl.h304
-rw-r--r--mountd/mountd.c76
-rw-r--r--mountd/mountd.h37
-rw-r--r--rootdir/Android.mk6
-rw-r--r--rootdir/etc/dbus.conf50
-rw-r--r--rootdir/etc/hcid.conf64
-rw-r--r--rootdir/etc/init.goldfish.rc9
-rw-r--r--rootdir/etc/mountd.conf6
-rw-r--r--rootdir/init.rc12
-rw-r--r--toolbox/Android.mk5
80 files changed, 4248 insertions, 579 deletions
diff --git a/Android.mk b/Android.mk
index 44ea560be..8b79cebad 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,8 +19,9 @@ ifneq ($(TARGET_SIMULATOR),true)
include $(call first-makefiles-under,$(LOCAL_PATH))
else
include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+ adb \
libcutils \
- liblog \
+ liblog \
libnetutils \
libpixelflinger \
libzipfile \
diff --git a/adb/Android.mk b/adb/Android.mk
index 8ac5eb437..c06485fbb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -7,6 +7,7 @@ LOCAL_PATH:= $(call my-dir)
# adb host tool
# =========================================================
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean (also unused with the sim)
include $(CLEAR_VARS)
# Default to a virtual (sockets) usb interface
@@ -29,7 +30,7 @@ ifeq ($(HOST_OS),windows)
USB_SRCS := usb_windows.c
EXTRA_SRCS := get_my_path_windows.c
EXTRA_STATIC_LIBS := AdbWinApi
- LOCAL_C_INCLUDES += /usr/include/w32api/ddk $(LOCAL_PATH)/../windows/usb/api
+ LOCAL_C_INCLUDES += /usr/include/w32api/ddk development/host/windows/usb/api/
ifneq ($(strip $(USE_CYGWIN)),)
LOCAL_LDLIBS += -lpthread
else
@@ -51,7 +52,8 @@ LOCAL_SRC_FILES := \
file_sync_client.c \
$(EXTRA_SRCS) \
$(USB_SRCS) \
- shlist.c
+ shlist.c \
+ utils.c \
ifneq ($(USE_SYSDEPS_WIN32),)
@@ -69,6 +71,8 @@ endif
include $(BUILD_HOST_EXECUTABLE)
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+
ifeq ($(HOST_OS),windows)
$(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
endif
@@ -81,10 +85,25 @@ LOCAL_MODULE := kdbg
include $(BUILD_HOST_EXECUTABLE)
endif
+endif
# adbd device daemon
# =========================================================
-ifeq ($(TARGET_ARCH),arm)
+
+# build adbd in all non-simulator builds
+BUILD_ADBD := false
+ifneq ($(TARGET_SIMULATOR),true)
+ BUILD_ADBD := true
+endif
+
+# build adbd for the Linux simulator build
+# so we can use it to test the adb USB gadget driver on x86
+ifeq ($(HOST_OS),linux)
+ BUILD_ADBD := true
+endif
+
+
+ifeq ($(BUILD_ADBD),true)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
@@ -99,18 +118,31 @@ LOCAL_SRC_FILES := \
framebuffer_service.c \
remount_service.c \
usb_linux_client.c \
- log_service.c
+ log_service.c \
+ utils.c \
-
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -DANDROID_GADGET=1 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+
+# TODO: This should probably be board specific, whether or not the kernel has
+# the gadget driver; rather than relying on the architecture type.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_CFLAGS += -DANDROID_GADGET=1
+endif
+
LOCAL_MODULE := adbd
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libcutils libc
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_STATIC_LIBRARIES := libcutils
+ LOCAL_LDLIBS += -lpthread
+ include $(BUILD_HOST_EXECUTABLE)
+else
+ LOCAL_STATIC_LIBRARIES := libcutils libc
+ include $(BUILD_EXECUTABLE)
+endif
-include $(BUILD_EXECUTABLE)
endif
diff --git a/adb/OVERVIEW.TXT b/adb/OVERVIEW.TXT
new file mode 100644
index 000000000..6a5191aee
--- /dev/null
+++ b/adb/OVERVIEW.TXT
@@ -0,0 +1,139 @@
+Implementation notes regarding ADB.
+
+I. General Overview:
+
+The Android Debug Bridge (ADB) is used to:
+
+- keep track of all Android devices and emulators instances
+ connected to or running on a given host developer machine
+
+- implement various control commands (e.g. "adb shell", "adb pull", etc..)
+ for the benefit of clients (command-line users, or helper programs like
+ DDMS). These commands are what is called a 'service' in ADB.
+
+As a whole, everything works through the following components:
+
+ 1. The ADB server
+
+ This is a background process that runs on the host machine. Its purpose
+ if to sense the USB ports to know when devices are attached/removed,
+ as well as when emulator instances start/stop.
+
+ It thus maintains a list of "connected devices" and assigns a 'state'
+ to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on
+ this below).
+
+ The ADB server is really one giant multiplexing loop whose purpose is
+ to orchestrate the exchange of data (packets, really) between clients,
+ services and devices.
+
+
+ 2. The ADB daemon (adbd)
+
+ The 'adbd' program runs as a background process within an Android device
+ or emulated system. Its purpose is to connect to the ADB server
+ (through USB for devices, through TCP for emulators) and provide a
+ few services for clients that run on the host.
+
+ The ADB server considers that a device is ONLINE when it has succesfully
+ connected to the adbd program within it. Otherwise, the device is OFFLINE,
+ meaning that the ADB server detected a new device/emulator, but could not
+ connect to the adbd daemon.
+
+ the BOOTLOADER and RECOVERY states correspond to alternate states of
+ devices when they are in the bootloader or recovery mode.
+
+ 3. The ADB command-line client
+
+ The 'adb' command-line program is used to run adb commands from a shell
+ or a script. It first tries to locate the ADB server on the host machine,
+ and will start one automatically if none is found.
+
+ then, the client sends its service requests to the ADB server. It doesn't
+ need to know.
+
+ Currently, a single 'adb' binary is used for both the server and client.
+ this makes distribution and starting the server easier.
+
+
+ 4. Services
+
+ There are essentially two kinds of services that a client can talk to.
+
+ Host Services:
+ these services run within the ADB Server and thus do not need to
+ communicate with a device at all. A typical example is "adb devices"
+ which is used to return the list of currently known devices and their
+ state. They are a few couple other services though.
+
+ Local Services:
+ these services either run within the adbd daemon, or are started by
+ it on the device. The ADB server is used to multiplex streams
+ between the client and the service running in adbd. In this case
+ its role is to initiate the connection, then of being a pass-through
+ for the data.
+
+
+II. Protocol details:
+
+ 1. Client <-> Server protocol:
+
+ This details the protocol used between ADB clients and the ADB
+ server itself. The ADB server listens on TCP:localhost:5037.
+
+ A client sends a request using the following format:
+
+ 1. A 4-byte hexadecimal string giving the length of the payload
+ 2. Followed by the payload itself.
+
+ For example, to query the ADB server for its internal version number,
+ the client will do the following:
+
+ 1. Connect to tcp:localhost:5037
+ 2. Send the string "000Chost:version" to the corresponding socket
+
+ The 'host:' prefix is used to indicate that the request is addressed
+ to the server itself (we will talk about other kinds of requests later).
+ The content length is encoded in ASCII for easier debugging.
+
+ The server should answer a request with one of the following:
+
+ 1. For success, the 4-byte "OKAY" string
+
+ 2. For failure, the 4-byte "FAIL" string, followed by a
+ 4-byte hex length, followed by a string giving the reason
+ for failure.
+
+ 3. As a special exception, for 'host:version', a 4-byte
+ hex string corresponding to the server's internal version number
+
+ Note that the connection is still alive after an OKAY, which allows the
+ client to make other requests. But in certain cases, an OKAY will even
+ change the state of the connection.
+
+ For example, the case of the 'host:transport:<serialnumber>' request,
+ where '<serialnumber>' is used to identify a given device/emulator; after
+ the "OKAY" answer, all further requests made by the client will go
+ directly to the corresponding adbd daemon.
+
+ The file SERVICES.TXT lists all services currently implemented by ADB.
+
+
+ 2. Transports:
+
+ An ADB transport models a connection between the ADB server and one device
+ or emulator. There are currently two kinds of transports:
+
+ - USB transports, for physical devices through USB
+
+ - Local transports, for emulators running on the host, connected to
+ the server through TCP
+
+ In theory, it should be possible to write a local transport that proxies
+ a connection between an ADB server and a device/emulator connected to/
+ running on another machine. This hasn't been done yet though.
+
+ Each transport can carry one or more multiplexed streams between clients
+ and the device/emulator they point to. The ADB server must handle
+ unexpected transport disconnections (e.g. when a device is physically
+ unplugged) properly.
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
new file mode 100644
index 000000000..d059e181f
--- /dev/null
+++ b/adb/SERVICES.TXT
@@ -0,0 +1,245 @@
+This file tries to document all requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here.
+
+HOST SERVICES:
+
+host:version
+ Ask the ADB server for its internal version number.
+
+ As a special exception, the server will respond with a 4-byte
+ hex string corresponding to its internal version number, without
+ any OKAY or FAIL.
+
+host:kill
+ Ask the ADB server to quit immediately. This is used when the
+ ADB client detects that an obsolete server is running after an
+ upgrade.
+
+host:devices
+ Ask to return the list of available Android devices and their
+ state. After the OKAY, this is followed by a 4-byte hex len,
+ and a string that will be dumped as-is by the client, then
+ the connection is closed
+
+host:track-devices
+ This is a variant of host:devices which doesn't close the
+ connection. Instead, a new device list description is sent
+ each time a device is added/removed or the state of a given
+ device changes (hex4 + content). This allows tools like DDMS
+ to track the state of connected devices in real-time without
+ polling the server repeatedly.
+
+host:emulator:<port>
+ This is a special query that is sent to the ADB server when a
+ new emulator starts up. <port> is a decimal number corresponding
+ to the emulator's ADB control port, i.e. the TCP port that the
+ emulator will forward automatically to the adbd daemon running
+ in the emulator system.
+
+ This mechanism allows the ADB server to know when new emulator
+ instances start.
+
+host:transport:<serial-number>
+ Ask to switch the connection to the device/emulator identified by
+ <serial-number>. After the OKAY response, every client request will
+ be sent directly to the adbd daemon running on the device.
+ (Used to implement the -s option)
+
+host:transport-usb
+ Ask to switch the connection to one device connected through USB
+ to the host machine. This will fail if there are more than one such
+ devices. (Used to implement the -d convenience option)
+
+host:transport-local
+ Ask to switch the connection to one emulator connected through TCP.
+ This will fail if there is more than one such emulator instance
+ running. (Used to implement the -e convenience option)
+
+host:transport-any
+ Another host:transport variant. Ask to switch the connection to
+ either the device or emulator connect to/running on the host.
+ Will fail if there is more than one such device/emulator available.
+ (Used when neither -s, -d or -e are provided)
+
+host-serial:<serial-number>:<request>
+ This is a special form of query, where the 'host-serial:<serial-number>:'
+ prefix can be used to indicate that the client is asking the ADB server
+ for information related to a specific device. <request> can be in one
+ of the format described below.
+
+host-usb:<request>
+ A variant of host-serial used to target the single USB device connected
+ to the host. This will fail if there is none or more than one.
+
+host-local:<request>
+ A variant of host-serial used to target the single emulator instance
+ running on the host. This will fail if therre is none or more than one.
+
+host:<request>
+ When asking for information related to a device, 'host:' can also be
+ interpreted as 'any single device or emulator connected to/running on
+ the host'.
+
+<host-prefix>:get-product
+ XXX
+
+<host-prefix>:get-serialno
+ Returns the serial number of the corresponding device/emulator.
+ Note that emulator serial numbers are of the form "emulator-5554"
+
+<host-prefix>:get-state
+ Returns the state of a given device as a string.
+
+<host-prefix>:forward:<local>:<remote>
+ Asks the ADB server to forward local connections from <local>
+ to the <remote> address on a given device.
+
+ There, <host-prefix> can be one of the
+ host-serial/host-usb/host-local/host prefixes as described previously
+ and indicates which device/emulator to target.
+
+ the format of <local> is one of:
+
+ tcp:<port> -> TCP connection on localhost:<port>
+ local:<path> -> Unix local domain socket on <path>
+
+ the format of <remote> is one of:
+
+ tcp:<port> -> TCP localhost:<port> on device
+ local:<path> -> Unix local domain socket on device
+ jdwp:<pid> -> JDWP thread on VM process <pid>
+
+ or even any one of the local services described below.
+
+
+
+LOCAL SERVICES:
+
+All the queries below assumed that you already switched the transport
+to a real device, or that you have used a query prefix as described
+above.
+
+shell:command arg1 arg2 ...
+ Run 'command arg1 arg2 ...' in a shell on the device, and return
+ its output and error streams. Note that arguments must be separated
+ by spaces. If an argument contains a space, it must be quoted with
+ double-quotes. Arguments cannot contain double quotes or things
+ will go very wrong.
+
+ Note that this is the non-interactive version of "adb shell"
+
+shell:
+ Start an interactive shell session on the device. Redirect
+ stdin/stdout/stderr as appropriate. Note that the ADB server uses
+ this to implement "adb shell", but will also cook the input before
+ sending it to the device (see interactive_shell() in commandline.c)
+
+bootdebug:
+ Ask debugging information to the bootloader. The adbd daemon will
+ respond with FAIL to this request.
+
+bootloader:<command>
+ Send a request to the bootloader. This can also work if the device
+ is currently in the bootloader state. The adbd daemon will respond
+ with FAIL to such requests.
+
+remount:
+ Ask adbd to remount the device's filesystem in read-write mode,
+ instead of read-only. This is usually necessary before performing
+ an "adb sync" or "adb push" request.
+
+ This request may not succeed on certain builds which do not allow
+ that.
+
+dev:<path>
+ Opens a device file and connects the client directly to it for
+ read/write purposes. Useful for debugging, but may require special
+ priviledges and thus may not run on all devices. <path> is a full
+ path from the root of the filesystem.
+
+tcp:<port>
+ Tries to connect to tcp port <port> on localhost.
+
+tcp:<port>:<server-name>
+ Tries to connect to tcp port <port> on machine <server-name> from
+ the device. This can be useful to debug some networking/proxy
+ issues that can only be revealed on the device itself.
+
+local:<path>
+ Tries to connect to a Unix domain socket <path> on the device
+
+localreserved:<path>
+localabstract:<path>
+localfilesystem:<path>
+ Variants of local:<path> that are used to access other Android
+ socket namespaces.
+
+log:<name>
+ Opens one of the system logs (/dev/log/<name>) and allows the client
+ to read them directly. Used to implement 'adb logcat'. The stream
+ will be read-only for the client.
+
+framebuffer:
+ This service is used to send snapshots of the framebuffer to a client.
+ It requires sufficient priviledges but works as follow:
+
+ After the OKAY, the service sends 16-byte binary structure
+ containing the following fields (little-endian format):
+
+ depth: uint32_t: framebuffer depth
+ size: uint32_t: framebuffer size in bytes
+ width: uint32_t: framebuffer width in pixels
+ height: uint32_t: framebuffer height in pixels
+
+ With the current implementation, depth is always 16, and
+ size is always width*height*2
+
+ Then, each time the client wants a snapshot, it should send
+ one byte through the channel, which will trigger the service
+ to send it 'size' bytes of framebuffer data.
+
+ If the adbd daemon doesn't have sufficient priviledges to open
+ the framebuffer device, the connection is simply closed immediately.
+
+dns:<server-name>
+ This service is an exception because it only runs within the ADB server.
+ It is used to implement USB networking, i.e. to provide a network connection
+ to the device through the host machine (note: this is the exact opposite of
+ network thetering).
+
+ It is used to perform a gethostbyname(<address>) on the host and return
+ the corresponding IP address as a 4-byte string.
+
+recover:<size>
+ This service is used to upload a recovery image to the device. <size>
+ must be a number corresponding to the size of the file. The service works
+ by:
+
+ - creating a file named /tmp/update
+ - reading 'size' bytes from the client and writing them to /tmp/update
+ - when everything is read succesfully, create a file named /tmp/update.start
+
+ This service can only work when the device is in recovery mode. Otherwise,
+ the /tmp directory doesn't exist and the connection will be closed immediately.
+
+jdwp:<pid>
+ Connects to the JDWP thread running in the VM of process <pid>.
+
+track-jdwp
+ This is used to send the list of JDWP pids periodically to the client.
+ The format of the returned data is the following:
+
+ <hex4>: the length of all content as a 4-char hexadecimal string
+ <content>: a series of ASCII lines of the following format:
+ <pid> "\n"
+
+ This service is used by DDMS to know which debuggable processes are running
+ on the device/emulator.
+
+ Note that there is no single-shot service to retrieve the list only once.
+
+sync:
+ This starts the file synchronisation service, used to implement "adb push"
+ and "adb pull". Since this service is pretty complex, it will be detailed
+ in a companion document named SYNC.TXT
diff --git a/adb/adb.c b/adb/adb.c
index a50ef334b..27d0c8156 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -67,59 +67,59 @@ int adb_trace_mask;
*/
void adb_trace_init(void)
{
- const char* p = getenv("ADB_TRACE");
- const char* q;
-
- static const struct {
- const char* tag;
- int flag;
- } tags[] = {
- { "1", 0 },
- { "all", 0 },
- { "adb", TRACE_ADB },
- { "sockets", TRACE_SOCKETS },
- { "packets", TRACE_PACKETS },
- { "rwx", TRACE_RWX },
- { "usb", TRACE_USB },
- { "sync", TRACE_SYNC },
- { "sysdeps", TRACE_SYSDEPS },
+ const char* p = getenv("ADB_TRACE");
+ const char* q;
+
+ static const struct {
+ const char* tag;
+ int flag;
+ } tags[] = {
+ { "1", 0 },
+ { "all", 0 },
+ { "adb", TRACE_ADB },
+ { "sockets", TRACE_SOCKETS },
+ { "packets", TRACE_PACKETS },
+ { "rwx", TRACE_RWX },
+ { "usb", TRACE_USB },
+ { "sync", TRACE_SYNC },
+ { "sysdeps", TRACE_SYSDEPS },
{ "transport", TRACE_TRANSPORT },
{ "jdwp", TRACE_JDWP },
- { NULL, 0 }
- };
-
- if (p == NULL)
- return;
-
- /* use a comma/column/semi-colum/space separated list */
- while (*p) {
- int len, tagn;
-
- q = strpbrk(p, " ,:;");
- if (q == NULL) {
- q = p + strlen(p);
- }
- len = q - p;
-
- for (tagn = 0; tags[tagn].tag != NULL; tagn++)
- {
- int taglen = strlen(tags[tagn].tag);
-
- if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
- {
- int flag = tags[tagn].flag;
- if (flag == 0) {
- adb_trace_mask = ~0;
- return;
- }
- adb_trace_mask |= (1 << flag);
- break;
- }
- }
- p = q;
- if (*p)
- p++;
- }
+ { NULL, 0 }
+ };
+
+ if (p == NULL)
+ return;
+
+ /* use a comma/column/semi-colum/space separated list */
+ while (*p) {
+ int len, tagn;
+
+ q = strpbrk(p, " ,:;");
+ if (q == NULL) {
+ q = p + strlen(p);
+ }
+ len = q - p;
+
+ for (tagn = 0; tags[tagn].tag != NULL; tagn++)
+ {
+ int taglen = strlen(tags[tagn].tag);
+
+ if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
+ {
+ int flag = tags[tagn].flag;
+ if (flag == 0) {
+ adb_trace_mask = ~0;
+ return;
+ }
+ adb_trace_mask |= (1 << flag);
+ break;
+ }
+ }
+ p = q;
+ if (*p)
+ p++;
+ }
}
@@ -783,8 +783,8 @@ int launch_server()
// child process
int result = execl(path, "adb", "fork-server", "server", NULL);
- // this should not return
- fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+ // this should not return
+ fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
} else {
// parent side of the fork
@@ -894,7 +894,7 @@ int adb_main(int is_daemon)
if(access("/dev/android_adb", F_OK) == 0 ||
access("/dev/android", F_OK) == 0) {
usb_init();
- } else {
+ } else {
local_init();
}
init_jdwp();
diff --git a/adb/adb.h b/adb/adb.h
index 5a74b7b9a..a17c8ddc5 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -79,6 +79,11 @@ struct asocket {
*/
unsigned id;
+ /* flag: set when the socket's peer has closed
+ ** but packets are still queued for delivery
+ */
+ int closing;
+
/* the asocket we are connected to
*/
@@ -309,15 +314,15 @@ int writex(int fd, const void *ptr, size_t len);
* the adb_trace_init() function implemented in adb.c
*/
typedef enum {
- TRACE_ADB = 0,
- TRACE_SOCKETS,
- TRACE_PACKETS,
- TRACE_TRANSPORT,
- TRACE_RWX,
- TRACE_USB,
- TRACE_SYNC,
- TRACE_SYSDEPS,
- TRACE_JDWP,
+ TRACE_ADB = 0,
+ TRACE_SOCKETS,
+ TRACE_PACKETS,
+ TRACE_TRANSPORT,
+ TRACE_RWX,
+ TRACE_USB,
+ TRACE_SYNC,
+ TRACE_SYSDEPS,
+ TRACE_JDWP,
} AdbTrace;
#if ADB_TRACE
diff --git a/adb/adb_client.c b/adb/adb_client.c
index c1b87ee51..586874480 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -211,7 +211,7 @@ int adb_connect(const char *service)
return -1;
} else {
fprintf(stdout,"* daemon started successfully *\n");
- }
+ }
/* give the server some time to start properly and detect devices */
adb_sleep_ms(2000);
// fall through to _adb_connect
@@ -223,13 +223,13 @@ int adb_connect(const char *service)
// if we have a file descriptor, then parse version result
if(fd >= 0) {
- if(readx(fd, buf, 4)) goto error;
+ if(readx(fd, buf, 4)) goto error;
- buf[4] = 0;
- n = strtoul(buf, 0, 16);
- if(n > (int)sizeof(buf)) goto error;
- if(readx(fd, buf, n)) goto error;
- adb_close(fd);
+ buf[4] = 0;
+ n = strtoul(buf, 0, 16);
+ if(n > (int)sizeof(buf)) goto error;
+ if(readx(fd, buf, n)) goto error;
+ adb_close(fd);
if (sscanf(buf, "%04x", &version) != 1) goto error;
} else {
@@ -240,14 +240,14 @@ int adb_connect(const char *service)
}
if(version != ADB_SERVER_VERSION) {
- printf("adb server is out of date. killing...\n");
- fd = _adb_connect("host:kill");
- adb_close(fd);
+ printf("adb server is out of date. killing...\n");
+ fd = _adb_connect("host:kill");
+ adb_close(fd);
- /* XXX can we better detect its death? */
- adb_sleep_ms(2000);
+ /* XXX can we better detect its death? */
+ adb_sleep_ms(2000);
goto start_server;
- }
+ }
}
// if the command is start-server, we are done.
diff --git a/adb/commandline.c b/adb/commandline.c
index c1ef8b011..cbf079c40 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -296,8 +296,8 @@ static void *stdin_read_thread(void *x)
buf_ptr[cmdlen] = '\0';
if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
shListInsFirstItem( &history, (void *)buf_ptr );
- item = &history;
- }
+ item = &history;
+ }
}
}
cmdlen = 0;
@@ -322,8 +322,8 @@ static void *stdin_read_thread(void *x)
default:
#ifdef SH_HISTORY
if( buf[n] == SH_DEL_CHAR ) {
- if( cmdlen > 0 )
- cmdlen--;
+ if( cmdlen > 0 )
+ cmdlen--;
}
else {
realbuf[cmdlen] = buf[n];
@@ -478,7 +478,7 @@ static void status_window(transport_type ttype, const char* serial)
#ifdef _WIN32
/* XXX: TODO */
#else
- int fd;
+ int fd;
fd = unix_open("/dev/null", O_WRONLY);
dup2(fd, 2);
adb_close(fd);
@@ -512,7 +512,7 @@ static void status_window(transport_type ttype, const char* serial)
}
}
-/** duplicate string and quote all \ " ( ) chars */
+/** duplicate string and quote all \ " ( ) chars + space character. */
static char *
dupAndQuote(const char *s)
{
@@ -527,7 +527,7 @@ dupAndQuote(const char *s)
for( ;*ts != '\0'; ts++) {
alloc_len++;
- if (*ts == '"' || *ts == '\\') {
+ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
alloc_len++;
}
}
@@ -538,7 +538,7 @@ dupAndQuote(const char *s)
dest = ret;
for ( ;*ts != '\0'; ts++) {
- if (*ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+ if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
*dest++ = '\\';
}
@@ -561,7 +561,7 @@ int ppp(int argc, char **argv)
{
#ifdef HAVE_WIN32_PROC
fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
- return -1;
+ return -1;
#else
char *adb_service_name;
pid_t pid;
@@ -657,8 +657,8 @@ static int logcat(transport_type transport, char* serial, int argc, char **argv)
quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
snprintf(buf, sizeof(buf),
- "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
- quoted_log_tags);
+ "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
+ quoted_log_tags);
free(quoted_log_tags);
@@ -847,7 +847,7 @@ int adb_commandline(int argc, char **argv)
if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
gProductOutPath = NULL;
}
- // TODO: also try TARGET_PRODUCT as a hint
+ // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
/* modifiers and flags */
while(argc > 0) {
@@ -1077,15 +1077,15 @@ top:
return 1;
}
- /* Allow a command to be run after wait-for-device,
- * e.g. 'adb wait-for-device shell'.
- */
- if(argc > 1) {
- argc--;
- argv++;
- goto top;
- }
- return 0;
+ /* Allow a command to be run after wait-for-device,
+ * e.g. 'adb wait-for-device shell'.
+ */
+ if(argc > 1) {
+ argc--;
+ argv++;
+ goto top;
+ }
+ return 0;
}
if(!strcmp(argv[0], "forward")) {
@@ -1299,7 +1299,7 @@ static int pm_command(transport_type transport, char* serial,
while(argc-- > 0) {
char *quoted;
- quoted = dupAndQuote (*argv++);
+ quoted = dupAndQuote(*argv++);
strncat(buf, " ", sizeof(buf)-1);
strncat(buf, quoted, sizeof(buf)-1);
@@ -1312,6 +1312,18 @@ static int pm_command(transport_type transport, char* serial,
int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
{
+ /* if the user choose the -k option, we refuse to do it until devices are
+ out with the option to uninstall the remaining data somehow (adb/ui) */
+ if (argc == 3 && strcmp(argv[1], "-k") == 0)
+ {
+ printf(
+ "The -k option uninstalls the application while retaining the data/cache.\n"
+ "At the moment, there is no way to remove the remaining data.\n"
+ "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+ "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
+ return -1;
+ }
+
/* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
return pm_command(transport, serial, argc, argv);
}
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index f9e80edbf..4e6d38591 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -55,7 +55,7 @@ static void END()
if(total_bytes == 0) return;
if (t == 0) /* prevent division by 0 :-) */
- t = 1000000;
+ t = 1000000;
fprintf(stderr,"%lld KB/s (%d bytes in %lld.%03llds)\n",
((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
@@ -227,14 +227,14 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
if(ret < 0) {
if(errno == EINTR)
- continue;
+ continue;
fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
break;
}
sbuf->size = htoll(ret);
if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
- err = -1;
+ err = -1;
break;
}
total_bytes += ret;
@@ -259,7 +259,7 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s
memcpy(sbuf->data, &file_buffer[total], count);
sbuf->size = htoll(count);
if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
- err = -1;
+ err = -1;
break;
}
total += count;
@@ -277,7 +277,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
if(len < 0) {
fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
- return -1;
+ return -1;
}
sbuf->data[len] = '\0';
@@ -377,10 +377,10 @@ static int sync_send(int fd, const char *lpath, const char *rpath,
}
if (file_buffer) {
- write_data_buffer(fd, file_buffer, size, sbuf);
- free(file_buffer);
+ write_data_buffer(fd, file_buffer, size, sbuf);
+ free(file_buffer);
} else if (S_ISREG(mode))
- write_data_file(fd, lpath, sbuf);
+ write_data_file(fd, lpath, sbuf);
#ifdef HAVE_SYMLINKS
else if (S_ISLNK(mode))
write_data_link(fd, lpath, sbuf);
@@ -641,7 +641,7 @@ static int local_build_list(copyinfo **filelist,
} else {
ci = mkcopyinfo(lpath, rpath, name, 0);
if(lstat(ci->src, &st)) {
- closedir(d);
+ closedir(d);
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
return -1;
}
@@ -651,7 +651,7 @@ static int local_build_list(copyinfo **filelist,
} else {
ci->time = st.st_mtime;
ci->mode = st.st_mode;
- ci->size = st.st_size;
+ ci->size = st.st_size;
ci->next = *filelist;
*filelist = ci;
}
@@ -707,12 +707,12 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i
unsigned int timestamp, mode, size;
if(sync_finish_readtime(fd, &timestamp, &mode, &size))
return 1;
- if(size == ci->size) {
+ if(size == ci->size) {
/* for links, we cannot update the atime/mtime */
if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
- (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
ci->flag = 1;
- }
+ }
}
}
for(ci = filelist; ci != 0; ci = next) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 21f8af775..a231e93d6 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -164,12 +164,12 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
}
if(fd < 0) {
if(fail_errno(s))
- return -1;
+ return -1;
fd = -1;
}
for(;;) {
- unsigned int len;
+ unsigned int len;
if(readx(s, &msg.data, sizeof(msg.data)))
goto fail;
@@ -264,7 +264,7 @@ static int handle_send_link(int s, char *path, char *buffer)
return -1;
} else {
fail_message(s, "invalid data message: expected ID_DONE");
- return -1;
+ return -1;
}
return 0;
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index 1d2c4b56b..0de0dd5e6 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -24,6 +24,7 @@
#include "adb.h"
#include <linux/fb.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
/* TODO:
@@ -37,9 +38,9 @@ void framebuffer_service(int fd, void *cookie)
int fb;
void *ptr = MAP_FAILED;
char x;
-
+
unsigned fbinfo[4];
-
+
fb = open("/dev/graphics/fb0", O_RDONLY);
if(fb < 0) goto done;
@@ -53,14 +54,14 @@ void framebuffer_service(int fd, void *cookie)
ptr = mmap(0, fbinfo[1], PROT_READ, MAP_SHARED, fb, 0);
if(ptr == MAP_FAILED) goto done;
-
+
if(writex(fd, fbinfo, sizeof(unsigned) * 4)) goto done;
for(;;) {
if(readx(fd, &x, 1)) goto done;
if(writex(fd, ptr, fbinfo[1])) goto done;
}
-
+
done:
if(ptr != MAP_FAILED) munmap(ptr, fbinfo[1]);
if(fb >= 0) close(fb);
diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.c
index 64a597d3c..fc7143c10 100644
--- a/adb/get_my_path_windows.c
+++ b/adb/get_my_path_windows.c
@@ -20,12 +20,12 @@
void get_my_path(char exe[PATH_MAX])
{
- char* r;
+ char* r;
- GetModuleFileName( NULL, exe, PATH_MAX-1 );
- exe[PATH_MAX-1] = 0;
- r = strrchr( exe, '\\' );
- if (r)
- *r = 0;
+ GetModuleFileName( NULL, exe, PATH_MAX-1 );
+ exe[PATH_MAX-1] = 0;
+ r = strrchr( exe, '\\' );
+ if (r)
+ *r = 0;
}
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c
index 43dc69eb4..ae7f12dfd 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.c
@@ -287,7 +287,7 @@ jdwp_process_event( int socket, unsigned events, void* _proc )
if (len <= 0) {
if (len < 0 && errno == EINTR)
continue;
- if (len < 0 && errno == EAGAIN)
+ if (len < 0 && errno == EAGAIN)
return;
else {
D("terminating JDWP %d connection: %s\n", proc->pid,
@@ -295,7 +295,7 @@ jdwp_process_event( int socket, unsigned events, void* _proc )
break;
}
}
- else {
+ else {
D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
proc->pid, len );
}
diff --git a/adb/sockets.c b/adb/sockets.c
index b9c9ae1cf..9f1b59870 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -50,6 +50,15 @@ static asocket local_socket_list = {
.prev = &local_socket_list,
};
+/* the the list of currently closing local sockets.
+** these have no peer anymore, but still packets to
+** write to their fd.
+*/
+static asocket local_socket_closing_list = {
+ .next = &local_socket_closing_list,
+ .prev = &local_socket_closing_list,
+};
+
asocket *find_local_socket(unsigned id)
{
asocket *s;
@@ -64,16 +73,22 @@ asocket *find_local_socket(unsigned id)
return result;
}
+static void
+insert_local_socket(asocket* s, asocket* list)
+{
+ s->next = list;
+ s->prev = s->next->prev;
+ s->prev->next = s;
+ s->next->prev = s;
+}
+
+
void install_local_socket(asocket *s)
{
adb_mutex_lock(&socket_list_lock);
s->id = local_socket_next_id++;
-
- s->next = &local_socket_list;
- s->prev = local_socket_list.prev;
- s->prev->next = s;
- s->next->prev = s;
+ insert_local_socket(s, &local_socket_list);
adb_mutex_unlock(&socket_list_lock);
}
@@ -177,19 +192,11 @@ static void local_socket_close(asocket *s)
adb_mutex_unlock(&socket_list_lock);
}
-static void local_socket_close_locked(asocket *s)
+// be sure to hold the socket list lock when calling this
+static void local_socket_destroy(asocket *s)
{
apacket *p, *n;
- if(s->peer) {
- s->peer->peer = 0;
- // tweak to avoid deadlock
- if (s->peer->close == local_socket_close)
- local_socket_close_locked(s->peer);
- else
- s->peer->close(s->peer);
- }
-
/* IMPORTANT: the remove closes the fd
** that belongs to this socket
*/
@@ -201,16 +208,94 @@ static void local_socket_close_locked(asocket *s)
n = p->next;
put_apacket(p);
}
-
- D("LS(%d): closed\n", s->id);
remove_socket(s);
free(s);
}
+
+static void local_socket_close_locked(asocket *s)
+{
+ if(s->peer) {
+ s->peer->peer = 0;
+ // tweak to avoid deadlock
+ if (s->peer->close == local_socket_close)
+ local_socket_close_locked(s->peer);
+ else
+ s->peer->close(s->peer);
+ }
+
+ /* If we are already closing, or if there are no
+ ** pending packets, destroy immediately
+ */
+ if (s->closing || s->pkt_first == NULL) {
+ int id = s->id;
+ local_socket_destroy(s);
+ D("LS(%d): closed\n", id);
+ return;
+ }
+
+ /* otherwise, put on the closing list
+ */
+ D("LS(%d): closing\n", s->id);
+ s->closing = 1;
+ fdevent_del(&s->fde, FDE_READ);
+ remove_socket(s);
+ insert_local_socket(s, &local_socket_closing_list);
+}
+
static void local_socket_event_func(int fd, unsigned ev, void *_s)
{
asocket *s = _s;
+ /* put the FDE_WRITE processing before the FDE_READ
+ ** in order to simplify the code.
+ */
+ if(ev & FDE_WRITE){
+ apacket *p;
+
+ while((p = s->pkt_first) != 0) {
+ while(p->len > 0) {
+ int r = adb_write(fd, p->ptr, p->len);
+ if(r > 0) {
+ p->ptr += r;
+ p->len -= r;
+ continue;
+ }
+ if(r < 0) {
+ /* returning here is ok because FDE_READ will
+ ** be processed in the next iteration loop
+ */
+ if(errno == EAGAIN) return;
+ if(errno == EINTR) continue;
+ }
+ s->close(s);
+ return;
+ }
+
+ if(p->len == 0) {
+ s->pkt_first = p->next;
+ if(s->pkt_first == 0) s->pkt_last = 0;
+ put_apacket(p);
+ }
+ }
+
+ /* if we sent the last packet of a closing socket,
+ ** we can now destroy it.
+ */
+ if (s->closing) {
+ s->close(s);
+ return;
+ }
+
+ /* no more packets queued, so we can ignore
+ ** writable events again and tell our peer
+ ** to resume writing
+ */
+ fdevent_del(&s->fde, FDE_WRITE);
+ s->peer->ready(s->peer);
+ }
+
+
if(ev & FDE_READ){
apacket *p = get_apacket();
unsigned char *x = p->data;
@@ -244,7 +329,12 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
if(r < 0) {
/* error return means they closed us as a side-effect
- ** and we must retutn immediately
+ ** and we must return immediately.
+ **
+ ** note that if we still have buffered packets, the
+ ** socket will be placed on the closing socket list.
+ ** this handler function will be called again
+ ** to process FDE_WRITE events.
*/
return;
}
@@ -261,42 +351,6 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
if(is_eof) {
s->close(s);
}
- return;
- }
-
- if(ev & FDE_WRITE){
- apacket *p;
-
- while((p = s->pkt_first) != 0) {
- while(p->len > 0) {
- int r = adb_write(fd, p->ptr, p->len);
- if(r > 0) {
- p->ptr += r;
- p->len -= r;
- continue;
- }
- if(r < 0) {
- if(errno == EAGAIN) return;
- if(errno == EINTR) continue;
- }
- s->close(s);
- return;
- }
-
- if(p->len == 0) {
- s->pkt_first = p->next;
- if(s->pkt_first == 0) s->pkt_last = 0;
- put_apacket(p);
- }
- }
-
- /* no more packets queued, so we can ignore
- ** writable events again and tell our peer
- ** to resume writing
- */
- fdevent_del(&s->fde, FDE_WRITE);
- s->peer->ready(s->peer);
- return;
}
if(ev & FDE_ERROR){
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 9d6a596cf..c2a9a985f 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -940,12 +940,12 @@ bip_buffer_write( BipBuffer bip, const void* src, int len )
/* we can append to region A */
if (avail > len)
avail = len;
-
+
memcpy( bip->buff + bip->a_end, src, avail );
src += avail;
count += avail;
len -= avail;
-
+
bip->a_end += avail;
if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
bip->can_write = 0;
@@ -953,25 +953,25 @@ bip_buffer_write( BipBuffer bip, const void* src, int len )
goto Exit;
}
}
-
+
if (len == 0)
goto Exit;
avail = bip->a_start - bip->b_end;
assert( avail > 0 ); /* since can_write is TRUE */
-
+
if (avail > len)
avail = len;
-
+
memcpy( bip->buff + bip->b_end, src, avail );
count += avail;
bip->b_end += avail;
-
+
if (bip->b_end == bip->a_start) {
bip->can_write = 0;
ResetEvent( bip->evt_write );
}
-
+
Exit:
assert( count > 0 );
@@ -979,7 +979,7 @@ Exit:
bip->can_read = 1;
SetEvent( bip->evt_read );
}
-
+
BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
LeaveCriticalSection( &bip->lock );
@@ -991,12 +991,12 @@ static int
bip_buffer_read( BipBuffer bip, void* dst, int len )
{
int avail, count = 0;
-
+
if (len <= 0)
return 0;
-
+
BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
+
EnterCriticalSection( &bip->lock );
while ( !bip->can_read )
{
@@ -1007,7 +1007,7 @@ bip_buffer_read( BipBuffer bip, void* dst, int len )
#else
int ret;
LeaveCriticalSection( &bip->lock );
-
+
if (bip->closed) {
errno = EPIPE;
return -1;
@@ -1023,30 +1023,30 @@ bip_buffer_read( BipBuffer bip, void* dst, int len )
return -1;
}
EnterCriticalSection( &bip->lock );
-#endif
+#endif
}
BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
+
avail = bip->a_end - bip->a_start;
assert( avail > 0 ); /* since can_read is TRUE */
-
+
if (avail > len)
avail = len;
-
+
memcpy( dst, bip->buff + bip->a_start, avail );
dst += avail;
count += avail;
len -= avail;
-
+
bip->a_start += avail;
if (bip->a_start < bip->a_end)
goto Exit;
-
+
bip->a_start = 0;
bip->a_end = bip->b_end;
bip->b_end = 0;
-
+
avail = bip->a_end;
if (avail > 0) {
if (avail > len)
@@ -1054,13 +1054,13 @@ bip_buffer_read( BipBuffer bip, void* dst, int len )
memcpy( dst, bip->buff, avail );
count += avail;
bip->a_start += avail;
-
+
if ( bip->a_start < bip->a_end )
goto Exit;
-
+
bip->a_start = bip->a_end = 0;
}
-
+
bip->can_read = 0;
ResetEvent( bip->evt_read );
@@ -1071,22 +1071,22 @@ Exit:
bip->can_write = 1;
SetEvent( bip->evt_write );
}
-
+
BIPDUMP( (const unsigned char*)dst - count, count );
BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n",
bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
LeaveCriticalSection( &bip->lock );
-
+
return count;
}
-
+
typedef struct SocketPairRec_
{
BipBufferRec a2b_bip;
BipBufferRec b2a_bip;
FH a_fd;
int used;
-
+
} SocketPairRec;
void _fh_socketpair_init( FH f )
@@ -1103,7 +1103,7 @@ _fh_socketpair_close( FH f )
if ( f == pair->a_fd ) {
pair->a_fd = NULL;
}
-
+
bip_buffer_close( &pair->b2a_bip );
bip_buffer_close( &pair->a2b_bip );
@@ -1199,7 +1199,7 @@ int adb_socketpair( int sv[2] )
sv[0] = _fh_to_int(fa);
sv[1] = _fh_to_int(fb);
-
+
pair->a2b_bip.fdin = sv[0];
pair->a2b_bip.fdout = sv[1];
pair->b2a_bip.fdin = sv[1];
@@ -1303,7 +1303,7 @@ event_hook_alloc( FH fh )
hook->stop = NULL;
hook->check = NULL;
hook->peek = NULL;
-
+
return hook;
}
@@ -1324,7 +1324,7 @@ event_hook_signal( EventHook hook )
FH f = hook->fh;
int fd = _fh_to_int(f);
fdevent* fde = fd_table[ fd - WIN32_FH_BASE ];
-
+
if (fde != NULL && fde->fd == fd) {
if ((fde->state & FDE_PENDING) == 0) {
fde->state |= FDE_PENDING;
@@ -1365,7 +1365,7 @@ event_looper_hook( EventLooper looper, int fd, int events )
FH f = _fh_from_int(fd);
EventHook *pnode;
EventHook node;
-
+
if (f == NULL) /* invalid arg */ {
D("event_looper_hook: invalid fd=%d\n", fd);
return;
@@ -1397,7 +1397,7 @@ event_looper_unhook( EventLooper looper, int fd, int events )
FH fh = _fh_from_int(fd);
EventHook *pnode = event_looper_find_p( looper, fh );
EventHook node = *pnode;
-
+
if (node != NULL) {
int events2 = events & node->wanted;
if ( events2 == 0 ) {
@@ -1424,7 +1424,7 @@ static void fdevent_connect(fdevent *fde)
{
EventLooper looper = &win32_looper;
int events = fde->state & FDE_EVENTMASK;
-
+
if (events != 0)
event_looper_hook( looper, fde->fd, events );
}
@@ -1433,7 +1433,7 @@ static void fdevent_disconnect(fdevent *fde)
{
EventLooper looper = &win32_looper;
int events = fde->state & FDE_EVENTMASK;
-
+
if (events != 0)
event_looper_unhook( looper, fde->fd, events );
}
@@ -1462,7 +1462,7 @@ static void fdevent_process()
EventLooper looper = &win32_looper;
EventHook hook;
int gotone = 0;
-
+
/* if we have at least one ready hook, execute it/them */
for (hook = looper->hooks; hook; hook = hook->next) {
hook->ready = 0;
@@ -1479,7 +1479,7 @@ static void fdevent_process()
if (!gotone)
{
looper->htab_count = 0;
-
+
for (hook = looper->hooks; hook; hook = hook->next)
{
if (hook->start && !hook->start(hook)) {
@@ -1519,7 +1519,7 @@ static void fdevent_process()
D( "adb_win32: wait failed, error %ld\n", GetLastError() );
} else {
D( "adb_win32: got one (index %d)\n", wait_ret );
-
+
/* according to Cygwin, some objects like consoles wake up on "inappropriate" events
* like mouse movements. we need to filter these with the "check" function
*/
@@ -1561,7 +1561,7 @@ static void fdevent_register(fdevent *fde)
if(fd < 0) {
FATAL("bogus negative fd (%d)\n", fde->fd);
}
-
+
if(fd >= fd_table_max) {
int oldmax = fd_table_max;
if(fde->fd > 32000) {
@@ -1587,7 +1587,7 @@ static void fdevent_register(fdevent *fde)
static void fdevent_unregister(fdevent *fde)
{
int fd = fde->fd - WIN32_FH_BASE;
-
+
if((fd < 0) || (fd >= fd_table_max)) {
FATAL("fd out of range (%d)\n", fde->fd);
}
@@ -1626,9 +1626,9 @@ static fdevent *fdevent_plist_dequeue(void)
{
fdevent *list = &list_pending;
fdevent *node = list->next;
-
+
if(node == list) return 0;
-
+
list->next = node->next;
list->next->prev = list;
node->next = 0;
@@ -1689,9 +1689,9 @@ void fdevent_remove(fdevent *fde)
void fdevent_set(fdevent *fde, unsigned events)
{
events &= FDE_EVENTMASK;
-
+
if((fde->state & FDE_EVENTMASK) == (int)events) return;
-
+
if(fde->state & FDE_ACTIVE) {
fdevent_update(fde, events);
dump_fde(fde, "update");
@@ -1727,13 +1727,13 @@ void fdevent_del(fdevent *fde, unsigned events)
void fdevent_loop()
{
fdevent *fde;
-
+
for(;;) {
#if DEBUG
fprintf(stderr,"--- ---- waiting for events\n");
#endif
fdevent_process();
-
+
while((fde = fdevent_plist_dequeue())) {
unsigned events = fde->events;
fde->events = 0;
@@ -1793,7 +1793,7 @@ static void _event_socket_verify( EventHook hook, WSANETWORKEVENTS* evts )
static void _event_socket_prepare( EventHook hook )
{
WSANETWORKEVENTS evts;
-
+
/* look if some of the events we want already happened ? */
if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
_event_socket_verify( hook, &evts );
@@ -1819,13 +1819,13 @@ static int _event_socket_start( EventHook hook )
/* create an event which we're going to wait for */
FH fh = hook->fh;
long flags = _socket_wanted_to_flags( hook->wanted );
-
+
hook->h = fh->event;
if (hook->h == INVALID_HANDLE_VALUE) {
D( "_event_socket_start: no event for %s\n", fh->name );
return 0;
}
-
+
if ( flags != fh->mask ) {
D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
@@ -1850,7 +1850,7 @@ static int _event_socket_check( EventHook hook )
int result = 0;
FH fh = hook->fh;
WSANETWORKEVENTS evts;
-
+
if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
_event_socket_verify( hook, &evts );
result = (hook->ready != 0);
@@ -1866,7 +1866,7 @@ static int _event_socket_peek( EventHook hook )
{
WSANETWORKEVENTS evts;
FH fh = hook->fh;
-
+
/* look if some of the events we want already happened ? */
if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
_event_socket_verify( hook, &evts );
@@ -1886,40 +1886,40 @@ static void _fh_socket_hook( FH f, int events, EventHook hook )
hook->stop = _event_socket_stop;
hook->check = _event_socket_check;
hook->peek = _event_socket_peek;
-
+
_event_socket_start( hook );
}
/** SOCKETPAIR EVENT HOOKS
**/
-
+
static void _event_socketpair_prepare( EventHook hook )
{
FH fh = hook->fh;
SocketPair pair = fh->fh_pair;
BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
+
if (hook->wanted & FDE_READ && rbip->can_read)
hook->ready |= FDE_READ;
-
+
if (hook->wanted & FDE_WRITE && wbip->can_write)
hook->ready |= FDE_WRITE;
}
-
+
static int _event_socketpair_start( EventHook hook )
{
FH fh = hook->fh;
SocketPair pair = fh->fh_pair;
BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
+
if (hook->wanted == FDE_READ)
hook->h = rbip->evt_read;
-
+
else if (hook->wanted == FDE_WRITE)
hook->h = wbip->evt_write;
-
+
else {
D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
return 0;
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 0e8b73246..be01f290c 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -76,7 +76,7 @@ static int remote_read(apacket *p, atransport *t)
}
if(check_data(p)) {
- D("bad data: terminated (data)\n");
+ D("bad data: terminated (data)\n");
return -1;
}
@@ -107,15 +107,16 @@ int local_connect(int port)
char buf[64];
int fd = -1;
- fd = socket_loopback_client(port, SOCK_STREAM);
#if ADB_HOST
- if(fd < 0) {
- const char *host = getenv("ADBHOST");
- if(host) {
- fd = socket_network_client(host, port, SOCK_STREAM);
- }
+ const char *host = getenv("ADBHOST");
+ if (host) {
+ fd = socket_network_client(host, port, SOCK_STREAM);
}
#endif
+ if (fd < 0) {
+ fd = socket_loopback_client(port, SOCK_STREAM);
+ }
+
if (fd >= 0) {
D("client: connected on remote on fd %d\n", fd);
close_on_exec(fd);
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 4da7e8b65..01c4a7ede 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -55,7 +55,7 @@ static int remote_read(apacket *p, atransport *t)
}
fix_endians(p);
-
+
if(check_header(p)) {
D("remote usb: check_header failed\n");
return -1;
@@ -79,9 +79,9 @@ static int remote_read(apacket *p, atransport *t)
static int remote_write(apacket *p, atransport *t)
{
unsigned size = p->msg.data_length;
-
+
fix_endians(p);
-
+
if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
D("remote usb: 1 - write terminated\n");
return -1;
@@ -91,7 +91,7 @@ static int remote_write(apacket *p, atransport *t)
D("remote usb: 2 - write terminated\n");
return -1;
}
-
+
return 0;
}
@@ -117,7 +117,7 @@ void init_usb_transport(atransport *t, usb_handle *h)
t->connection_state = CS_OFFLINE;
t->type = kTransportUsb;
t->usb = h;
-
+
#if ADB_HOST
HOST = 1;
#else
@@ -135,7 +135,7 @@ int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_
/* not supported */
return 0;
}
-
+
/* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
if(usb_class == 0xff) {
if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index e265a1c22..530bd04db 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -118,7 +118,7 @@ void usb_init()
h->fd = -1;
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
-
+
// Open the file /dev/android_adb_enable to trigger
// the enabling of the adb USB function in the kernel.
// We never touch this file again - just leave it open
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 8ea84f926..49e1eef5b 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -72,13 +72,13 @@ InitUSB()
CFRunLoopSourceRef runLoopSource;
SInt32 vendor, product;
int i;
-
+
//* To set up asynchronous notifications, create a notification port and
//* add its run loop event source to the program's run loop
notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-
+
memset(notificationIterators, 0, sizeof(notificationIterators));
//* loop through all supported vendor/product pairs
@@ -86,19 +86,19 @@ InitUSB()
//* Create our matching dictionary to find the Android device
//* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
-
+
if (!matchingDict) {
DBG("ERR: Couldn't create USB matching dictionary.\n");
return -1;
}
-
+
//* Set up two matching dictionaries, one for each product ID we support.
//* This will cause the kernel to notify us only if the vendor and product IDs match.
vendor = kSupportedDevices[i].vid;
product = kSupportedDevices[i].pid;
- CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
- CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
-
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
+
//* Now set up two notifications: one to be called when a raw device
//* is first matched by the I/O Kit and another to be called when the
//* device is terminated.
@@ -110,7 +110,7 @@ InitUSB()
AndroidDeviceAdded,
NULL,
&notificationIterators[i]);
-
+
//* Iterate over set of matching devices to access already-present devices
//* and to arm the notification
AndroidDeviceAdded(NULL, notificationIterators[i]);
@@ -173,7 +173,7 @@ AndroidDeviceAdded(void *refCon, io_iterator_t iterator)
if (kr == kIOReturnSuccess && req.wLenDone > 0) {
int i, count;
-
+
// skip first word, and copy the rest to the serial string, changing shorts to bytes.
count = (req.wLenDone - 1) / 2;
for (i = 0; i < count; i++)
@@ -401,8 +401,8 @@ void* RunLoopThread(void* unused)
currentRunLoop = 0;
for (i = 0; i < kSupportedDeviceCount; i++) {
- IOObjectRelease(notificationIterators[i]);
- }
+ IOObjectRelease(notificationIterators[i]);
+ }
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 5b0f11fa6..7ddaa0c18 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -308,11 +308,11 @@ int usb_read(usb_handle *handle, void* data, int len) {
while (len > 0) {
int xfer = (len > 4096) ? 4096 : len;
- ret = AdbReadEndpointSync(handle->adb_read_pipe,
- (void*)data,
- (unsigned long)xfer,
- &read,
- time_out);
+ ret = AdbReadEndpointSync(handle->adb_read_pipe,
+ (void*)data,
+ (unsigned long)xfer,
+ &read,
+ time_out);
errno = GetLastError();
D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
if (ret) {
@@ -475,11 +475,11 @@ void find_devices() {
// Lets see if we already have this device in the list
if (!known_device(interf_name)) {
// This seems to be a new device. Open it!
- handle = do_usb_open(next_interface->device_name);
- if (NULL != handle) {
+ handle = do_usb_open(next_interface->device_name);
+ if (NULL != handle) {
// Lets see if this interface (device) belongs to us
if (recognized_device(handle)) {
- D("adding a new device %s\n", interf_name);
+ D("adding a new device %s\n", interf_name);
char serial_number[512];
unsigned long serial_number_len = sizeof(serial_number);
if (AdbGetSerialNumber(handle->adb_interface,
@@ -488,7 +488,7 @@ void find_devices() {
true)) {
// Lets make sure that we don't duplicate this device
if (register_new_device(handle)) {
- register_usb_transport(handle, serial_number);
+ register_usb_transport(handle, serial_number);
} else {
D("register_new_device failed for %s\n", interf_name);
usb_cleanup_handle(handle);
diff --git a/adb/utils.c b/adb/utils.c
new file mode 100644
index 000000000..91518bab6
--- /dev/null
+++ b/adb/utils.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "utils.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+char*
+buff_addc (char* buff, char* buffEnd, int c)
+{
+ int avail = buffEnd - buff;
+
+ if (avail <= 0) /* already in overflow mode */
+ return buff;
+
+ if (avail == 1) { /* overflowing, the last byte is reserved for zero */
+ buff[0] = 0;
+ return buff + 1;
+ }
+
+ buff[0] = (char) c; /* add char and terminating zero */
+ buff[1] = 0;
+ return buff + 1;
+}
+
+char*
+buff_adds (char* buff, char* buffEnd, const char* s)
+{
+ int slen = strlen(s);
+
+ return buff_addb(buff, buffEnd, s, slen);
+}
+
+char*
+buff_addb (char* buff, char* buffEnd, const void* data, int len)
+{
+ int avail = (buffEnd - buff);
+
+ if (avail <= 0 || len <= 0) /* already overflowing */
+ return buff;
+
+ if (len > avail)
+ len = avail;
+
+ memcpy(buff, data, len);
+
+ buff += len;
+
+ /* ensure there is a terminating zero */
+ if (buff >= buffEnd) { /* overflow */
+ buff[-1] = 0;
+ } else
+ buff[0] = 0;
+
+ return buff;
+}
+
+char*
+buff_add (char* buff, char* buffEnd, const char* format, ... )
+{
+ int avail;
+
+ avail = (buffEnd - buff);
+
+ if (avail > 0) {
+ va_list args;
+ int nn;
+
+ va_start(args, format);
+ nn = vsnprintf( buff, avail, format, args);
+ va_end(args);
+
+ if (nn < 0) {
+ /* some C libraries return -1 in case of overflow,
+ * but they will also do that if the format spec is
+ * invalid. We assume ADB is not buggy enough to
+ * trigger that last case. */
+ nn = avail;
+ }
+ else if (nn > avail) {
+ nn = avail;
+ }
+
+ buff += nn;
+
+ /* ensure that there is a terminating zero */
+ if (buff >= buffEnd)
+ buff[-1] = 0;
+ else
+ buff[0] = 0;
+ }
+ return buff;
+}
diff --git a/adb/utils.h b/adb/utils.h
new file mode 100644
index 000000000..f70ecd24d
--- /dev/null
+++ b/adb/utils.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ADB_UTILS_H
+#define _ADB_UTILS_H
+
+/* bounded buffer functions */
+
+/* all these functions are used to append data to a bounded buffer.
+ *
+ * after each operation, the buffer is guaranteed to be zero-terminated,
+ * even in the case of an overflow. they all return the new buffer position
+ * which allows one to use them in succession, only checking for overflows
+ * at the end. For example:
+ *
+ * BUFF_DECL(temp,p,end,1024);
+ * char* p;
+ *
+ * p = buff_addc(temp, end, '"');
+ * p = buff_adds(temp, end, string);
+ * p = buff_addc(temp, end, '"');
+ *
+ * if (p >= end) {
+ * overflow detected. note that 'temp' is
+ * zero-terminated for safety.
+ * }
+ * return strdup(temp);
+ */
+
+/* tries to add a character to the buffer, in case of overflow
+ * this will only write a terminating zero and return buffEnd.
+ */
+char* buff_addc (char* buff, char* buffEnd, int c);
+
+/* tries to add a string to the buffer */
+char* buff_adds (char* buff, char* buffEnd, const char* s);
+
+/* tries to add a bytes to the buffer. the input can contain zero bytes,
+ * but a terminating zero will always be appended at the end anyway
+ */
+char* buff_addb (char* buff, char* buffEnd, const void* data, int len);
+
+/* tries to add a formatted string to a bounded buffer */
+char* buff_add (char* buff, char* buffEnd, const char* format, ... );
+
+/* convenience macro used to define a bounded buffer, as well as
+ * a 'cursor' and 'end' variables all in one go.
+ *
+ * note: this doesn't place an initial terminating zero in the buffer,
+ * you need to use one of the buff_ functions for this. or simply
+ * do _cursor[0] = 0 manually.
+ */
+#define BUFF_DECL(_buff,_cursor,_end,_size) \
+ char _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
+
+#endif /* _ADB_UTILS_H */
diff --git a/cpio/Android.mk b/cpio/Android.mk
index f340fd69a..8d01852b0 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -10,4 +10,4 @@ LOCAL_MODULE := mkbootfs
include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,user userdebug droid,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 03046bd5e..b22e1a81d 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,5 +1,7 @@
# Copyright 2005 The Android Open Source Project
+ifeq ($(TARGET_ARCH),arm)
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -20,3 +22,5 @@ LOCAL_MODULE_TAGS := eng
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
+
+endif # TARGET_ARCH == arm
diff --git a/debuggerd/unwind-arm.c b/debuggerd/unwind-arm.c
index fdc0a6aa6..9642d2e4a 100644
--- a/debuggerd/unwind-arm.c
+++ b/debuggerd/unwind-arm.c
@@ -381,13 +381,15 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address, pid_t pid,
}
/* Print out the current call level, pc, and module name in the crash log */
-static _Unwind_Reason_Code log_function(_Unwind_Context *context, int tfd,
+static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid,
+ int tfd,
int stack_level,
mapinfo *map,
unsigned int sp_list[],
bool at_fault)
{
_uw pc;
+ _uw rel_pc;
phase2_vrs *vrs = (phase2_vrs*) context;
const mapinfo *mi;
bool only_in_tombstone = !at_fault;
@@ -404,19 +406,53 @@ static _Unwind_Reason_Code log_function(_Unwind_Context *context, int tfd,
// For deeper framers, rollback pc by one instruction
else {
pc = vrs->core.r[R_PC];
- // Thumb mode
+ /* Thumb mode - need to check whether the bl(x) has long offset or not.
+ * Examples:
+ *
+ * arm blx in the middle of thumb:
+ * 187ae: 2300 movs r3, #0
+ * 187b0: f7fe ee1c blx 173ec
+ * 187b4: 2c00 cmp r4, #0
+ *
+ * arm bl in the middle of thumb:
+ * 187d8: 1c20 adds r0, r4, #0
+ * 187da: f136 fd15 bl 14f208
+ * 187de: 2800 cmp r0, #0
+ *
+ * pure thumb:
+ * 18894: 189b adds r3, r3, r2
+ * 18896: 4798 blx r3
+ * 18898: b001 add sp, #4
+ */
if (pc & 1) {
- pc = (pc & ~1) - 2;
+ _uw prev_word;
+ pc = (pc & ~1);
+ prev_word = get_remote_word(pid, (void *) pc-4);
+ // Long offset
+ if ((prev_word & 0xf0000000) == 0xf0000000 &&
+ (prev_word & 0x0000e000) == 0x0000e000) {
+ pc -= 4;
+ }
+ else {
+ pc -= 2;
+ }
}
else {
pc -= 4;
}
}
- mi = pc_to_mapinfo(map, pc);
+ /* We used to print the absolute PC in the back trace, and mask out the top
+ * 3 bits to guesstimate the offset in the .so file. This is not working for
+ * non-prelinked libraries since the starting offset may not be aligned on
+ * 1MB boundaries, and the library may be larger than 1MB. So for .so
+ * addresses we print the relative offset in back trace.
+ */
+ rel_pc = pc;
+ mi = pc_to_mapinfo(map, pc, &rel_pc);
_LOG(tfd, only_in_tombstone,
- " #%02d pc %08x %s\n", stack_level, pc,
+ " #%02d pc %08x %s\n", stack_level, rel_pc,
mi ? mi->name : "");
return _URC_NO_REASON;
@@ -459,7 +495,7 @@ int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
*/
if (get_eitp(saved_vrs.core.r[R_PC], pid, map, NULL) == NULL) {
*frame0_pc_sane = 0;
- log_function ((_Unwind_Context *) &saved_vrs, tfd, stack_level,
+ log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level,
map, sp_list, at_fault);
saved_vrs.core.r[R_PC] = saved_vrs.core.r[R_LR];
stack_level++;
@@ -493,7 +529,7 @@ int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
_Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp);
/* Call log function. */
- if (log_function ((_Unwind_Context *) &saved_vrs, tfd, stack_level,
+ if (log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level,
map, sp_list, at_fault) != _URC_NO_REASON) {
code = _URC_FAILURE;
break;
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index 0cb790fd6..8f3931c1f 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -18,6 +18,7 @@
#include <sys/ptrace.h>
#include <sys/exec_elf.h>
#include <assert.h>
+#include <string.h>
#include <errno.h>
#include "utility.h"
@@ -66,10 +67,14 @@ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def)
}
/* Find the containing map info for the pc */
-const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc)
+const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
{
while(mi) {
if((pc >= mi->start) && (pc < mi->end)){
+ // Only calculate the relative offset for shared libraries
+ if (strstr(mi->name, ".so")) {
+ *rel_pc = pc - mi->start;
+ }
return mi;
}
mi = mi->next;
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 802e3ad2e..49f59518e 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -45,7 +45,7 @@ extern int get_remote_word(int pid, void *src);
extern void get_remote_struct(int pid, void *src, void *dst, size_t size);
/* Find the containing map for the pc */
-const mapinfo *pc_to_mapinfo (mapinfo *mi, unsigned pc);
+const mapinfo *pc_to_mapinfo (mapinfo *mi, unsigned pc, unsigned *rel_pc);
/* Map a pc address to the name of the containing ELF file */
const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 5e9941de9..7a9d35f28 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -43,7 +43,7 @@ endif
LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz
include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,user userdebug droid,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 64a4045c5..4079a3894 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -47,6 +47,7 @@ static const char *serial = 0;
static const char *product = 0;
static const char *cmdline = 0;
static int wipe_data = 0;
+static unsigned short vendor_id = 0;
void die(const char *fmt, ...)
{
@@ -135,7 +136,8 @@ oops:
int match_fastboot(usb_ifc_info *info)
{
- if((info->dev_vendor != 0x18d1) &&
+ if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
+ (info->dev_vendor != 0x18d1) &&
(info->dev_vendor != 0x0bb4)) return -1;
if(info->ifc_class != 0xff) return -1;
if(info->ifc_subclass != 0x42) return -1;
@@ -208,6 +210,7 @@ void usage(void)
" -s <serial number> specify device serial number\n"
" -p <product> specify product name\n"
" -c <cmdline> override kernel commandline\n"
+ " -i <vendor id> specify a custom USB vendor id\n"
);
exit(1);
}
@@ -553,6 +556,16 @@ int main(int argc, char **argv)
require(2);
cmdline = argv[1];
skip(2);
+ } else if(!strcmp(*argv, "-i")) {
+ char *endptr = NULL;
+ unsigned long val;
+
+ require(2);
+ val = strtoul(argv[1], &endptr, 0);
+ if (!endptr || *endptr != '\0' || (val & ~0xffff))
+ die("invalid vendor id '%s'", argv[1]);
+ vendor_id = (unsigned short)val;
+ skip(2);
} else if(!strcmp(*argv, "getvar")) {
require(2);
fb_queue_display(argv[1], argv[1]);
diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h
index d7e182a93..b2dabf210 100644
--- a/include/arch/linux-arm/AndroidConfig.h
+++ b/include/arch/linux-arm/AndroidConfig.h
@@ -48,6 +48,12 @@
#define HAVE_FUTEX
/*
+ * Define if we already have the futex wrapper functions defined. Yes if
+ * compiling against bionic.
+ */
+#define HAVE_FUTEX_WRAPPERS 1
+
+/*
* Process creation model. Choose one:
*
* HAVE_FORKEXEC - use fork() and exec()
diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h
new file mode 100644
index 000000000..4aa44f883
--- /dev/null
+++ b/include/arch/target_linux-x86/AndroidConfig.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * Android config -- "target_linux-x86". Used for x86 linux target devices.
+ */
+#ifndef _ANDROID_CONFIG_H
+#define _ANDROID_CONFIG_H
+
+/*
+ * ===========================================================================
+ * !!! IMPORTANT !!!
+ * ===========================================================================
+ *
+ * This file is included by ALL C/C++ source files. Don't put anything in
+ * here unless you are absolutely certain it can't go anywhere else.
+ *
+ * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
+ * comments.
+ */
+
+/*
+ * Threading model. Choose one:
+ *
+ * HAVE_PTHREADS - use the pthreads library.
+ * HAVE_WIN32_THREADS - use Win32 thread primitives.
+ * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
+ */
+#define HAVE_PTHREADS
+
+/*
+ * Do we have the futex syscall?
+ */
+
+#define HAVE_FUTEX
+
+/*
+ * Define if we already have the futex wrapper functions defined. Yes if
+ * compiling against bionic.
+ */
+#define HAVE_FUTEX_WRAPPERS 1
+
+/*
+ * Process creation model. Choose one:
+ *
+ * HAVE_FORKEXEC - use fork() and exec()
+ * HAVE_WIN32_PROC - use CreateProcess()
+ */
+#define HAVE_FORKEXEC
+
+/*
+ * Process out-of-memory adjustment. Set if running on Linux,
+ * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
+ * badness adjustment.
+ */
+#define HAVE_OOM_ADJ
+
+/*
+ * IPC model. Choose one:
+ *
+ * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
+ * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
+ * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
+ * HAVE_ANDROID_IPC - use Android versions (?, mmap).
+ */
+#define HAVE_ANDROID_IPC 1
+
+/*
+ * Memory-mapping model. Choose one:
+ *
+ * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
+ * HAVE_WIN32_FILEMAP - use Win32 filemaps
+ */
+#define HAVE_POSIX_FILEMAP 1
+
+/*
+ * Define this if you have <termio.h>
+ */
+#define HAVE_TERMIO_H 1
+
+/*
+ * Define this if you build against have Microsoft C runtime (MSVCRT.DLL)
+ */
+/* #define HAVE_MS_C_RUNTIME */
+
+/*
+ * Define this if you have sys/uio.h
+ */
+#define HAVE_SYS_UIO_H 1
+
+/*
+ * Define this if your platforms implements symbolic links
+ * in its filesystems
+ */
+#define HAVE_SYMLINKS 1
+
+/*
+ * Define this if we have localtime_r().
+ */
+/* #define HAVE_LOCALTIME_R */
+
+/*
+ * Define this if we have gethostbyname_r().
+ */
+/* #define HAVE_GETHOSTBYNAME_R */
+
+/*
+ * Define this if we have ioctl().
+ */
+#define HAVE_IOCTL
+
+/*
+ * Define this if we want to use WinSock.
+ */
+/* #define HAVE_WINSOCK */
+
+/*
+ * Define this if have clock_gettime() and friends
+ *
+ */
+#define HAVE_POSIX_CLOCKS
+
+/*
+ * Define this if we have pthread_cond_timedwait_monotonic() and
+ * clock_gettime(CLOCK_MONOTONIC).
+ */
+#define HAVE_TIMEDWAIT_MONOTONIC
+
+/*
+ * Define this if we have linux style epoll()
+ */
+#define HAVE_EPOLL
+
+/*
+ * Endianness of the target machine. Choose one:
+ *
+ * HAVE_ENDIAN_H -- have endian.h header we can include.
+ * HAVE_LITTLE_ENDIAN -- we are little endian.
+ * HAVE_BIG_ENDIAN -- we are big endian.
+ */
+#define HAVE_ENDIAN_H
+#define HAVE_LITTLE_ENDIAN
+
+/*
+ * We need to choose between 32-bit and 64-bit off_t. All of our code should
+ * agree on the same size. For desktop systems, use 64-bit values,
+ * because some of our libraries (e.g. wxWidgets) expect to be built that way.
+ */
+/*
+ * #define _FILE_OFFSET_BITS 64
+ * #define _LARGEFILE_SOURCE 1
+ */
+
+/*
+ * Defined if we have the backtrace() call for retrieving a stack trace.
+ * Needed for CallStack to operate; if not defined, CallStack is
+ * non-functional.
+ */
+#define HAVE_BACKTRACE 0
+
+/*
+ * Defined if we have the dladdr() call for retrieving the symbol associated
+ * with a memory address. If not defined, stack crawls will not have symbolic
+ * information.
+ */
+#define HAVE_DLADDR 0
+
+/*
+ * Defined if we have the cxxabi.h header for demangling C++ symbols. If
+ * not defined, stack crawls will be displayed with raw mangled symbols
+ */
+#define HAVE_CXXABI 0
+
+/*
+ * Defined if we have the gettid() system call.
+ */
+#define HAVE_GETTID
+
+/*
+ * Defined if we have the sched_setscheduler() call
+ */
+#define HAVE_SCHED_SETSCHEDULER
+
+/*
+ * Add any extra platform-specific defines here.
+ */
+#ifndef __linux__
+#define __linux__
+#endif
+
+/*
+ * Define if we have <malloc.h> header
+ */
+#define HAVE_MALLOC_H
+
+/*
+ * Define if we're running on *our* linux on device or emulator.
+ */
+#define HAVE_ANDROID_OS 1
+
+/*
+ * Define if we have Linux-style non-filesystem Unix Domain Sockets
+ */
+#define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
+
+/*
+ * Define if we have Linux's inotify in <sys/inotify.h>.
+ */
+#define HAVE_INOTIFY 1
+
+/*
+ * Define if we have madvise() in <sys/mman.h>
+ */
+#define HAVE_MADVISE 1
+
+/*
+ * Define if we have Linux's dbus
+ */
+#define HAVE_DBUS 1
+
+/*
+ * Define if tm struct has tm_gmtoff field
+ */
+#define HAVE_TM_GMTOFF 1
+
+/*
+ * Define if dirent struct has d_type field
+ */
+#define HAVE_DIRENT_D_TYPE 1
+
+/*
+ * Define if libc includes Android system properties implementation.
+ */
+#define HAVE_LIBC_SYSTEM_PROPERTIES 1
+
+/*
+ * Define if system provides a system property server (should be
+ * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
+ */
+/* #define HAVE_SYSTEM_PROPERTY_SERVER */
+
+/*
+ * What CPU architecture does this platform use?
+ */
+#define ARCH_X86
+
+/*
+ * sprintf() format string for shared library naming.
+ */
+#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
+
+/*
+ * Do we have __memcmp16()?
+ */
+/* #define HAVE__MEMCMP16 1 */
+
+/*
+ * type for the third argument to mincore().
+ */
+#define MINCORE_POINTER_TYPE unsigned char *
+
+/*
+ * Do we have the sigaction flag SA_NOCLDWAIT?
+ */
+#define HAVE_SA_NOCLDWAIT
+
+/*
+ * The default path separator for the platform
+ */
+#define OS_PATH_SEPARATOR '/'
+
+/*
+ * Is the filesystem case sensitive?
+ */
+#define OS_CASE_SENSITIVE
+
+/*
+ * Define if <sys/socket.h> exists.
+ */
+#define HAVE_SYS_SOCKET_H 1
+
+/*
+ * Define if the strlcpy() function exists on the system.
+ */
+#define HAVE_STRLCPY 1
+
+/*
+ * Define if prctl() exists
+ */
+#define HAVE_PRCTL 1
+
+/*
+ * Whether or not _Unwind_Context is defined as a struct.
+ */
+#define HAVE_UNWIND_CONTEXT_STRUCT
+
+#endif /* _ANDROID_CONFIG_H */
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
index 59c0670d6..9b3ece84c 100644
--- a/include/cutils/tztime.h
+++ b/include/cutils/tztime.h
@@ -24,6 +24,21 @@ extern "C" {
time_t mktime_tz(struct tm * const tmp, char const * tz);
void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
+struct strftime_locale {
+ const char *mon[12]; /* short names */
+ const char *month[12]; /* long names */
+ const char *wday[7]; /* short names */
+ const char *weekday[7]; /* long names */
+ const char *X_fmt;
+ const char *x_fmt;
+ const char *c_fmt;
+ const char *am;
+ const char *pm;
+ const char *date_fmt;
+};
+
+size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/pixelflinger/format.h b/include/pixelflinger/format.h
index ad0d29d84..308e56002 100644
--- a/include/pixelflinger/format.h
+++ b/include/pixelflinger/format.h
@@ -30,6 +30,7 @@ enum GGLPixelFormat {
GGL_PIXEL_FORMAT_RGBX_8888 = 2, // 3x8-bit RGB stored in 32-bit chunks
GGL_PIXEL_FORMAT_RGB_888 = 3, // 3x8-bit RGB
GGL_PIXEL_FORMAT_RGB_565 = 4, // 16-bit RGB
+ GGL_PIXEL_FORMAT_BGRA_8888 = 5, // 4x8-bit BGRA
GGL_PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit RGBA
GGL_PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit RGBA
@@ -38,9 +39,11 @@ enum GGLPixelFormat {
GGL_PIXEL_FORMAT_LA_88 = 0xA, // 16-bit LA
GGL_PIXEL_FORMAT_RGB_332 = 0xB, // 8-bit RGB (non paletted)
- // YCbCr formats
+ // YCbCr formats (SP=semi-planar, P=planar)
GGL_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
GGL_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
+ GGL_PIXEL_FORMAT_YCbCr_422_P = 0x14,
+ GGL_PIXEL_FORMAT_YCbCr_420_P = 0x15,
// reserved/special formats
GGL_PIXEL_FORMAT_Z_16 = 0x18,
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 13e134bba..c8551872a 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -150,8 +150,10 @@ static struct fs_path_config android_files[] = {
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },
{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.gprs-pppd" },
{ 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },
- { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/hcid.conf" },
{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
+ { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/hcid.conf" },
+ { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" },
+ { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" },
{ 00440, AID_RADIO, AID_AUDIO, "/system/etc/AudioPara4.csv" },
{ 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" },
diff --git a/include/private/pixelflinger/ggl_context.h b/include/private/pixelflinger/ggl_context.h
index 241a0abdb..3a030c526 100644
--- a/include/private/pixelflinger/ggl_context.h
+++ b/include/private/pixelflinger/ggl_context.h
@@ -147,11 +147,11 @@ GGL_RESERVE_NEEDS( P_FOG, 9, 1 )
GGL_RESERVE_NEEDS( P_RESERVED1, 10,22 )
GGL_RESERVE_NEEDS( T_FORMAT, 0, 6 )
-GGL_RESERVE_NEEDS( T_RESERVED0, 6, 2 )
+GGL_RESERVE_NEEDS( T_RESERVED0, 6, 1 )
+GGL_RESERVE_NEEDS( T_POT, 7, 1 )
GGL_RESERVE_NEEDS( T_S_WRAP, 8, 2 )
GGL_RESERVE_NEEDS( T_T_WRAP, 10, 2 )
-GGL_RESERVE_NEEDS( T_ENV, 12, 2 )
-GGL_RESERVE_NEEDS( T_POT, 14, 1 )
+GGL_RESERVE_NEEDS( T_ENV, 12, 3 )
GGL_RESERVE_NEEDS( T_LINEAR, 15, 1 )
const int GGL_NEEDS_WRAP_CLAMP_TO_EDGE = 0;
@@ -182,12 +182,14 @@ inline uint32_t ggl_env_to_needs(uint32_t e) {
case GGL_MODULATE: return 1;
case GGL_DECAL: return 2;
case GGL_BLEND: return 3;
+ case GGL_ADD: return 4;
}
return 0;
}
inline uint32_t ggl_needs_to_env(uint32_t n) {
- const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE, GGL_DECAL, GGL_BLEND };
+ const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE,
+ GGL_DECAL, GGL_BLEND, GGL_ADD };
return envs[n];
}
diff --git a/init/README.BOOTCHART b/init/README.BOOTCHART
index 489936973..70cf2c39b 100644
--- a/init/README.BOOTCHART
+++ b/init/README.BOOTCHART
@@ -1,32 +1,50 @@
-this version of init contains code to perform "bootcharting", i.e. generating log
+This version of init contains code to perform "bootcharting", i.e. generating log
files that can be later processed by the tools provided by www.bootchart.org.
-to activate it, you need to define build 'init' with the INIT_BOOTCHART environment
-variable defined to 'true', then create a file on the /data partition with a command
-like the following:
+To activate it, you need to define build 'init' with the INIT_BOOTCHART environment
+variable defined to 'true', for example:
- adb shell 'echo 1 > /data/bootchart'
+ touch system/init/init.c
+ m INIT_BOOTCHART=true
-if the '/data/bootchart' file doesn't exist, or doesn't contain a '1' in its first
-byte, init will proceed normally.
+On the emulator, use the new -bootchart <timeout> option to boot with bootcharting
+activated for <timeout> seconds.
-by default, the bootchart log stops after 2 minutes, but you can stop it earlier
-with the following command while the device is booting:
+Otherwise, flash your device, and start it. Then create a file on the /data partition
+with a command like the following:
+
+ adb shell 'echo $TIMEOUT > /data/bootchart-start'
+
+Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds;
+for example, to bootchart for 2 minutes, do:
+
+ adb shell 'echo 120 > /data/bootchart-start'
+
+Reboot your device, bootcharting will begin and stop after the period you gave.
+You can also stop the bootcharting at any moment by doing the following:
adb shell 'echo 1 > /data/bootchart-stop'
-note that /data/bootchart-stop is deleted automatically by init at the end of the
-bootcharting. this is not the case of /data/bootchart, so don't forget to delete it
+Note that /data/bootchart-stop is deleted automatically by init at the end of the
+bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it
when you're done collecting data:
- adb shell rm /data/bootchart
+ adb shell rm /data/bootchart-start
-the log files are placed in /tmp/bootchart/. you must run the script tools/grab-bootchart.sh
+The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh
which will use ADB to retrieve them and create a bootchart.tgz file that can be used with
the bootchart parser/renderer, or even uploaded directly to the form located at:
http://www.bootchart.org/download.html
+NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an
+ image on your machine by doing the following:
+
+ 1/ download the sources from www.bootchart.org
+ 2/ unpack them
+ 3/ in the source directory, type 'ant' to build the bootchart program
+ 4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz
+
technical note:
this implementation of bootcharting does use the 'bootchartd' script provided by
diff --git a/init/bootchart.c b/init/bootchart.c
index 2afe98b6b..f72fcaaca 100644
--- a/init/bootchart.c
+++ b/init/bootchart.c
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
/* this code is used to generate a boot sequence profile that can be used
* with the 'bootchart' graphics generation tool. see www.bootchart.org
* note that unlike the original bootchartd, this is not a Bash script but
@@ -16,17 +32,18 @@
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
+#include "bootchart.h"
#define VERSION "0.8"
#define SAMPLE_PERIOD 0.2
-#define LOG_ROOT "/tmp/bootchart"
+#define LOG_ROOT "/data/bootchart"
#define LOG_STAT LOG_ROOT"/proc_stat.log"
#define LOG_PROCS LOG_ROOT"/proc_ps.log"
#define LOG_DISK LOG_ROOT"/proc_diskstats.log"
#define LOG_HEADER LOG_ROOT"/header"
#define LOG_ACCT LOG_ROOT"/kernel_pacct"
-#define LOG_STARTFILE "/data/bootchart"
+#define LOG_STARTFILE "/data/bootchart-start"
#define LOG_STOPFILE "/data/bootchart-stop"
static int
@@ -54,12 +71,11 @@ proc_read(const char* filename, char* buff, size_t buffsize)
len = unix_read(fd, buff, buffsize-1);
close(fd);
}
- buff[len] = 0;
+ buff[len > 0 ? len : 0] = 0;
return len;
}
#define FILE_BUFF_SIZE 65536
-#define FILE_BUFF_RESERVE (FILE_BUFF_SIZE - 4096)
typedef struct {
int count;
@@ -81,7 +97,7 @@ file_buff_write( FileBuff buff, const void* src, int len )
int avail = sizeof(buff->data) - buff->count;
if (avail > len)
avail = len;
-
+
memcpy( buff->data + buff->count, src, avail );
len -= avail;
src = (char*)src + avail;
@@ -115,7 +131,7 @@ log_header(void)
time_t now_t = time(NULL);
struct tm now = *localtime(&now_t);
strftime(date, sizeof(date), "%x %X", &now);
-
+
out = fopen( LOG_HEADER, "w" );
if (out == NULL)
return;
@@ -123,7 +139,7 @@ log_header(void)
proc_read("/proc/cmdline", cmdline, sizeof(cmdline));
proc_read("/proc/version", uname, sizeof(uname));
proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo));
-
+
cpu = strchr( cpuinfo, ':' );
if (cpu) {
char* p = strchr(cpu, '\n');
@@ -131,7 +147,7 @@ log_header(void)
if (p)
*p = 0;
}
-
+
fprintf(out, "version = %s\n", VERSION);
fprintf(out, "title = Boot chart for Android ( %s )\n", date);
fprintf(out, "system.uname = %s\n", uname);
@@ -174,7 +190,6 @@ do_log_uptime(FileBuff log)
fd = open("/proc/uptime",O_RDONLY);
if (fd >= 0) {
int ret;
- close_on_exec(fd);
ret = unix_read(fd, buff, 64);
close(fd);
buff[64] = 0;
@@ -212,7 +227,7 @@ do_log_file(FileBuff log, const char* procfile)
ret = unix_read(fd, buff, sizeof(buff));
if (ret <= 0)
break;
-
+
file_buff_write(log, buff, ret);
if (ret < (int)sizeof(buff))
break;
@@ -230,7 +245,7 @@ do_log_procs(FileBuff log)
struct dirent* entry;
do_log_uptime(log);
-
+
while ((entry = readdir(dir)) != NULL) {
/* only match numeric values */
char* end;
@@ -241,7 +256,7 @@ do_log_procs(FileBuff log)
char cmdline[1024];
int len;
int fd;
-
+
/* read command line and extract program name */
snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid);
proc_read(filename, cmdline, sizeof(cmdline));
@@ -285,11 +300,36 @@ int bootchart_init( void )
{
int ret;
char buff[4];
-
+ int timeout = 0, count = 0;
+
buff[0] = 0;
proc_read( LOG_STARTFILE, buff, sizeof(buff) );
- if (buff[0] != '1')
- return -1;
+ if (buff[0] != 0) {
+ timeout = atoi(buff);
+ }
+ else {
+ /* when running with emulator, androidboot.bootchart=<timeout>
+ * might be passed by as kernel parameters to specify the bootchart
+ * timeout. this is useful when using -wipe-data since the /data
+ * partition is fresh
+ */
+ char cmdline[1024];
+ char* s;
+#define KERNEL_OPTION "androidboot.bootchart="
+ proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );
+ s = strstr(cmdline, KERNEL_OPTION);
+ if (s) {
+ s += sizeof(KERNEL_OPTION)-1;
+ timeout = atoi(s);
+ }
+ }
+ if (timeout == 0)
+ return 0;
+
+ if (timeout > BOOTCHART_MAX_TIME_SEC)
+ timeout = BOOTCHART_MAX_TIME_SEC;
+
+ count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR);
@@ -307,7 +347,7 @@ int bootchart_init( void )
}
log_header();
- return 0;
+ return count;
}
/* called each time you want to perform a bootchart sampling op */
@@ -324,6 +364,7 @@ int bootchart_step( void )
return -1;
}
}
+
return 0;
}
diff --git a/init/bootchart.h b/init/bootchart.h
new file mode 100644
index 000000000..39d2d4f20
--- /dev/null
+++ b/init/bootchart.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _BOOTCHART_H
+#define _BOOTCHART_H
+
+#ifndef BOOTCHART
+# define BOOTCHART 0
+#endif
+
+#if BOOTCHART
+
+extern int bootchart_init(void);
+extern int bootchart_step(void);
+extern void bootchart_finish(void);
+
+# define BOOTCHART_POLLING_MS 200 /* polling period in ms */
+# define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */
+# define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */
+
+#endif /* BOOTCHART */
+
+#endif /* _BOOTCHART_H */
diff --git a/init/builtins.c b/init/builtins.c
index ba344100c..95fb22304 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -64,7 +64,7 @@ static int write_file(const char *path, const char *value)
}
}
-static int insmod(const char *filename)
+static int insmod(const char *filename, char *options)
{
void *module;
unsigned size;
@@ -74,7 +74,7 @@ static int insmod(const char *filename)
if (!module)
return -1;
- ret = init_module(module, size, "");
+ ret = init_module(module, size, options);
free(module);
@@ -172,9 +172,35 @@ int do_ifup(int nargs, char **args)
return __ifupdown(args[1], 1);
}
+
+static int do_insmod_inner(int nargs, char **args, int opt_len)
+{
+ char options[opt_len + 1];
+ int i;
+
+ options[0] = '\0';
+ if (nargs > 2) {
+ strcpy(options, args[2]);
+ for (i = 3; i < nargs; ++i) {
+ strcat(options, " ");
+ strcat(options, args[i]);
+ }
+ }
+
+ return insmod(args[1], options);
+}
+
int do_insmod(int nargs, char **args)
{
- return insmod(args[1]);
+ int i;
+ int size = 0;
+
+ if (nargs > 2) {
+ for (i = 2; i < nargs; ++i)
+ size += strlen(args[i]) + 1;
+ }
+
+ return do_insmod_inner(nargs, args, size);
}
int do_import(int nargs, char **args)
@@ -326,6 +352,20 @@ int do_symlink(int nargs, char **args)
return symlink(args[1], args[2]);
}
+int do_sysclktz(int nargs, char **args)
+{
+ struct timezone tz;
+
+ if (nargs != 2)
+ return -1;
+
+ memset(&tz, 0, sizeof(tz));
+ tz.tz_minuteswest = atoi(args[1]);
+ if (settimeofday(NULL, &tz))
+ return -1;
+ return 0;
+}
+
int do_write(int nargs, char **args)
{
return write_file(args[1], args[2]);
diff --git a/init/devices.c b/init/devices.c
index 7aea24623..f86eab991 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -98,9 +98,12 @@ static struct perms_ devperms[] = {
/* these should not be world writable */
{ "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 },
{ "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },
- { "/dev/ttyMSM0", 0660, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
+ /* TODO: remove legacy ttyMSM0 */
+ { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
+ { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
+ { "/dev/uinput", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
{ "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },
- { "/dev/tty0", 0666, AID_ROOT, AID_SYSTEM, 0 },
+ { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 },
{ "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },
{ "/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
{ "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },
@@ -360,29 +363,29 @@ static void handle_device_event(struct uevent *uevent)
return;
/* are we block or char? where should we live? */
- if(!strncmp(uevent->path, "/block", 6)) {
+ if(!strncmp(uevent->subsystem, "block", 5)) {
block = 1;
base = "/dev/block/";
mkdir(base, 0755);
} else {
block = 0;
/* this should probably be configurable somehow */
- if(!strncmp(uevent->path, "/class/graphics/", 16)) {
+ if(!strncmp(uevent->subsystem, "graphics", 8)) {
base = "/dev/graphics/";
mkdir(base, 0755);
- } else if (!strncmp(uevent->path, "/class/oncrpc/", 14)) {
+ } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
base = "/dev/oncrpc/";
mkdir(base, 0755);
- } else if (!strncmp(uevent->path, "/class/adsp/", 12)) {
+ } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
base = "/dev/adsp/";
mkdir(base, 0755);
- } else if(!strncmp(uevent->path, "/class/input/", 13)) {
+ } else if(!strncmp(uevent->subsystem, "input", 5)) {
base = "/dev/input/";
mkdir(base, 0755);
- } else if(!strncmp(uevent->path, "/class/mtd/", 11)) {
+ } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
base = "/dev/mtd/";
mkdir(base, 0755);
- } else if(!strncmp(uevent->path, "/class/misc/", 12) &&
+ } else if(!strncmp(uevent->subsystem, "misc", 4) &&
!strncmp(name, "log_", 4)) {
base = "/dev/log/";
mkdir(base, 0755);
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index 57c955688..7fe890436 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -9,13 +9,13 @@ TMPDIR=/tmp/android-bootchart
rm -rf $TMPDIR
mkdir -p $TMPDIR
-LOGROOT=/tmp/bootchart
+LOGROOT=/data/bootchart
TARBALL=bootchart.tgz
FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
for f in $FILES; do
- adb pull $LOGROOT/$f $TMPDIR/$f &> /dev/null
+ adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
done
(cd $TMPDIR && tar -czf $TARBALL $FILES)
cp -f $TMPDIR/$TARBALL ./$TARBALL
diff --git a/init/init.c b/init/init.c
index f6e9b398b..361684095 100644
--- a/init/init.c
+++ b/init/init.c
@@ -43,21 +43,12 @@
#include "devices.h"
#include "init.h"
#include "property_service.h"
-
-#ifndef BOOTCHART
-# define BOOTCHART 0
-#endif
+#include "bootchart.h"
static int property_triggers_enabled = 0;
#if BOOTCHART
static int bootchart_count;
-extern int bootchart_init(void);
-extern int bootchart_step(void);
-extern void bootchart_finish(void);
-# define BOOTCHART_POLLING_MS 200 /* polling period in ms */
-# define BOOTCHART_MAX_TIME_MS (2*60*1000) /* max polling time from boot */
-# define BOOTCHART_MAX_COUNT (BOOTCHART_MAX_TIME_MS/BOOTCHART_POLLING_MS)
#endif
static char console[32];
@@ -834,11 +825,13 @@ int main(int argc, char **argv)
ufds[2].events = POLLIN;
#if BOOTCHART
- if (bootchart_init() < 0)
+ bootchart_count = bootchart_init();
+ if (bootchart_count < 0) {
ERROR("bootcharting init failure\n");
- else {
- NOTICE("bootcharting started\n");
- bootchart_count = BOOTCHART_MAX_COUNT;
+ } else if (bootchart_count > 0) {
+ NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
+ } else {
+ NOTICE("bootcharting ignored\n");
}
#endif
diff --git a/init/keywords.h b/init/keywords.h
index f09bad242..058996e3b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -19,6 +19,7 @@ int do_start(int nargs, char **args);
int do_stop(int nargs, char **args);
int do_trigger(int nargs, char **args);
int do_symlink(int nargs, char **args);
+int do_sysclktz(int nargs, char **args);
int do_write(int nargs, char **args);
int do_chown(int nargs, char **args);
int do_chmod(int nargs, char **args);
@@ -60,6 +61,7 @@ enum {
KEYWORD(stop, COMMAND, 1, do_stop)
KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(symlink, COMMAND, 1, do_symlink)
+ KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(user, OPTION, 0, 0)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(chown, COMMAND, 2, do_chown)
diff --git a/init/parser.c b/init/parser.c
index 95bf01791..a51691be2 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -183,6 +183,7 @@ int lookup_keyword(const char *s)
if (!strcmp(s, "tart")) return K_start;
if (!strcmp(s, "top")) return K_stop;
if (!strcmp(s, "ymlink")) return K_symlink;
+ if (!strcmp(s, "ysclktz")) return K_sysclktz;
break;
case 't':
if (!strcmp(s, "rigger")) return K_trigger;
diff --git a/init/property_service.c b/init/property_service.c
index 0bc403f63..7a6416b5e 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -343,7 +343,7 @@ void handle_property_set_fd(int fd)
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
- if ((s = accept(fd, &addr, &addr_size)) < 0) {
+ if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
diff --git a/init/readme.txt b/init/readme.txt
index 360a1b709..665090bad 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -194,6 +194,9 @@ stop <service>
symlink <target> <path>
Create a symbolic link at <path> with the value <target>
+sysclktz <mins_west_of_gmt>
+ Set the system clock base (0 if system clock ticks in GMT)
+
trigger <event>
Trigger an event. Used to queue an action from another
action.
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 3d0c12b1d..a43f7e3e4 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -60,6 +60,7 @@ else
selector.c \
fdevent.c \
tztime.c \
+ tzstrftime.c \
adb_networking.c \
zygote.c
endif
@@ -91,8 +92,14 @@ else #!sim
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) memset32.S atomic-android-arm.S mq.c \
- ashmem-dev.c
+LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += memset32.S atomic-android-arm.S
+else # !arm
+LOCAL_SRC_FILES += memory.c
+endif # !arm
+
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_STATIC_LIBRARIES := liblog
include $(BUILD_STATIC_LIBRARY)
diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S
index 2a4c34f06..c56ec5d0e 100644
--- a/libcutils/atomic-android-arm.S
+++ b/libcutils/atomic-android-arm.S
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <machine/cpu-features.h>
+
/*
* NOTE: these atomic operations are SMP safe on all architectures,
* except swap(), see below.
@@ -59,8 +61,14 @@ android_atomic_write:
1: @ android_atomic_write
ldr r0, [r2]
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #4
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
bcc 1b
ldmia sp!, {r4, lr}
bx lr
@@ -78,9 +86,16 @@ android_atomic_inc:
1: @ android_atomic_inc
ldr r0, [r2]
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #4
add r1, r0, #1
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ add r1, r0, #1
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
bcc 1b
sub r0, r1, #1
ldmia sp!, {r4, lr}
@@ -99,9 +114,16 @@ android_atomic_dec:
1: @ android_atomic_dec
ldr r0, [r2]
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #4
sub r1, r0, #1
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ sub r1, r0, #1
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
bcc 1b
add r0, r1, #1
ldmia sp!, {r4, lr}
@@ -121,9 +143,16 @@ android_atomic_add:
1: @ android_atomic_add
ldr r0, [r2]
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #4
add r1, r0, r4
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ add r1, r0, r4
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
bcc 1b
sub r0, r1, r4
ldmia sp!, {r4, lr}
@@ -144,10 +173,18 @@ android_atomic_and:
1: @ android_atomic_and
ldr r0, [r2] /* r0 = address[0] */
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #8
mov r5, r0 /* r5 = save address[0] */
and r1, r0, r4 /* r1 = new value */
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+#else
+ mov r5, r0 /* r5 = save address[0] */
+ and r1, r0, r4 /* r1 = new value */
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+ mov lr, pc
+ bx r3
+#endif
bcc 1b
mov r0, r5
ldmia sp!, {r4, r5, lr}
@@ -167,10 +204,18 @@ android_atomic_or:
1: @ android_atomic_or
ldr r0, [r2] /* r0 = address[0] */
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #8
mov r5, r0 /* r5 = save address[0] */
orr r1, r0, r4 /* r1 = new value */
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+#else
+ mov r5, r0 /* r5 = save address[0] */
+ orr r1, r0, r4 /* r1 = new value */
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+ mov lr, pc
+ bx r3
+#endif
bcc 1b
mov r0, r5
ldmia sp!, {r4, r5, lr}
@@ -202,9 +247,16 @@ android_atomic_cmpxchg:
mov r4, r0 /* r4 = save oldvalue */
1: @ android_atomic_cmpxchg
mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
add lr, pc, #4
mov r0, r4 /* r0 = oldvalue */
add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ mov r0, r4 /* r0 = oldvalue */
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
bcs 2f /* swap was made. we're good, return. */
ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
cmp r3, r4
diff --git a/libcutils/tzstrftime.c b/libcutils/tzstrftime.c
new file mode 100644
index 000000000..29c50154a
--- /dev/null
+++ b/libcutils/tzstrftime.c
@@ -0,0 +1,834 @@
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)strftime.c 8.1";
+/*
+** Based on the UCB version with the ID appearing below.
+** This is ANSIish only when "multibyte character == plain character".
+*/
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#include <time.h>
+#include <tzfile.h>
+#include <limits.h>
+#include <cutils/tztime.h>
+
+/*
+** Copyright (c) 1989 The Regents of the University of California.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms are permitted
+** provided that the above copyright notice and this paragraph are
+** duplicated in all such forms and that any documentation,
+** advertising materials, and other materials related to such
+** distribution and use acknowledge that the software was developed
+** by the University of California, Berkeley. The name of the
+** University may not be used to endorse or promote products derived
+** from this software without specific prior written permission.
+** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef LIBC_SCCS
+#ifndef lint
+static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
+#endif /* !defined lint */
+#endif /* !defined LIBC_SCCS */
+
+#include <ctype.h>
+
+#define P(x) x
+
+static char * _add P((const char *, char *, const char *, int));
+static char * _conv P((int, const char *, char *, const char *));
+static char * _fmt P((const char *, const struct tm *, char *, const char *,
+ int *, const struct strftime_locale *Locale));
+static char * _yconv P((int, int, int, int, char *, const char *, int));
+static char * getformat P((int, char *, char *, char *, char *));
+
+extern char * tzname[];
+
+
+
+
+
+/* from private.h */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+ * ** 302 / 1000 is log10(2.0) rounded up.
+ * ** Subtract one for the sign bit if the type is signed;
+ * ** add one for integer division truncation;
+ * ** add one more for a minus sign if the type is signed.
+ * */
+#define INT_STRLEN_MAXIMUM(type) \
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+ 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/* end of part from private.h */
+
+
+
+
+#ifndef YEAR_2000_NAME
+#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
+#endif /* !defined YEAR_2000_NAME */
+
+#define IN_NONE 0
+#define IN_SOME 1
+#define IN_THIS 2
+#define IN_ALL 3
+
+#define FORCE_LOWER_CASE 0x100
+
+size_t
+strftime_tz(s, maxsize, format, t, Locale)
+char * const s;
+const size_t maxsize;
+const char * const format;
+const struct tm * const t;
+const struct strftime_locale *Locale;
+{
+ char * p;
+ int warn;
+
+ warn = IN_NONE;
+ p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
+#if 0
+ if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
+ (void) fprintf(stderr, "\n");
+ if (format == NULL)
+ (void) fprintf(stderr, "NULL strftime format ");
+ else (void) fprintf(stderr, "strftime format \"%s\" ",
+ format);
+ (void) fprintf(stderr, "yields only two digits of years in ");
+ if (warn == IN_SOME)
+ (void) fprintf(stderr, "some locales");
+ else if (warn == IN_THIS)
+ (void) fprintf(stderr, "the current locale");
+ else (void) fprintf(stderr, "all locales");
+ (void) fprintf(stderr, "\n");
+ }
+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
+ if (p == s + maxsize)
+ return 0;
+ *p = '\0';
+ return p - s;
+}
+
+static char *getformat(int modifier, char *normal, char *underscore,
+ char *dash, char *zero) {
+ switch (modifier) {
+ case '_':
+ return underscore;
+
+ case '-':
+ return dash;
+
+ case '0':
+ return zero;
+ }
+
+ return normal;
+}
+
+static char *
+_fmt(format, t, pt, ptlim, warnp, Locale)
+const char * format;
+const struct tm * const t;
+char * pt;
+const char * const ptlim;
+int * warnp;
+const struct strftime_locale *Locale;
+{
+ for ( ; *format; ++format) {
+ if (*format == '%') {
+ int modifier = 0;
+label:
+ switch (*++format) {
+ case '\0':
+ --format;
+ break;
+ case 'A':
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
+ "?" : Locale->weekday[t->tm_wday],
+ pt, ptlim, modifier);
+ continue;
+ case 'a':
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
+ "?" : Locale->wday[t->tm_wday],
+ pt, ptlim, modifier);
+ continue;
+ case 'B':
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
+ "?" : Locale->month[t->tm_mon],
+ pt, ptlim, modifier);
+ continue;
+ case 'b':
+ case 'h':
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
+ "?" : Locale->mon[t->tm_mon],
+ pt, ptlim, modifier);
+ continue;
+ case 'C':
+ /*
+ ** %C used to do a...
+ ** _fmt("%a %b %e %X %Y", t);
+ ** ...whereas now POSIX 1003.2 calls for
+ ** something completely different.
+ ** (ado, 1993-05-24)
+ */
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
+ pt, ptlim, modifier);
+ continue;
+ case 'c':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'D':
+ pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'd':
+ pt = _conv(t->tm_mday,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'E':
+ case 'O':
+ /*
+ ** C99 locale modifiers.
+ ** The sequences
+ ** %Ec %EC %Ex %EX %Ey %EY
+ ** %Od %oe %OH %OI %Om %OM
+ ** %OS %Ou %OU %OV %Ow %OW %Oy
+ ** are supposed to provide alternate
+ ** representations.
+ */
+ goto label;
+ case '_':
+ case '-':
+ case '0':
+ case '^':
+ case '#':
+ modifier = *format;
+ goto label;
+ case 'e':
+ pt = _conv(t->tm_mday,
+ getformat(modifier, "%2d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'F':
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'H':
+ pt = _conv(t->tm_hour,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'I':
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'j':
+ pt = _conv(t->tm_yday + 1,
+ getformat(modifier, "%03d", "%3d", "%d", "%03d"),
+ pt, ptlim);
+ continue;
+ case 'k':
+ /*
+ ** This used to be...
+ ** _conv(t->tm_hour % 12 ?
+ ** t->tm_hour % 12 : 12, 2, ' ');
+ ** ...and has been changed to the below to
+ ** match SunOS 4.1.1 and Arnold Robbins'
+ ** strftime version 3.0. That is, "%k" and
+ ** "%l" have been swapped.
+ ** (ado, 1993-05-24)
+ */
+ pt = _conv(t->tm_hour,
+ getformat(modifier, "%2d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+#ifdef KITCHEN_SINK
+ case 'K':
+ /*
+ ** After all this time, still unclaimed!
+ */
+ pt = _add("kitchen sink", pt, ptlim, modifier);
+ continue;
+#endif /* defined KITCHEN_SINK */
+ case 'l':
+ /*
+ ** This used to be...
+ ** _conv(t->tm_hour, 2, ' ');
+ ** ...and has been changed to the below to
+ ** match SunOS 4.1.1 and Arnold Robbin's
+ ** strftime version 3.0. That is, "%k" and
+ ** "%l" have been swapped.
+ ** (ado, 1993-05-24)
+ */
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ getformat(modifier, "%2d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'M':
+ pt = _conv(t->tm_min,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'm':
+ pt = _conv(t->tm_mon + 1,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'n':
+ pt = _add("\n", pt, ptlim, modifier);
+ continue;
+ case 'p':
+ pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+ Locale->pm :
+ Locale->am,
+ pt, ptlim, modifier);
+ continue;
+ case 'P':
+ pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+ Locale->pm :
+ Locale->am,
+ pt, ptlim, FORCE_LOWER_CASE);
+ continue;
+ case 'R':
+ pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'r':
+ pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'S':
+ pt = _conv(t->tm_sec,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 's':
+ {
+ struct tm tm;
+ char buf[INT_STRLEN_MAXIMUM(
+ time_t) + 1];
+ time_t mkt;
+
+ tm = *t;
+ mkt = mktime(&tm);
+ if (TYPE_SIGNED(time_t))
+ (void) sprintf(buf, "%ld",
+ (long) mkt);
+ else (void) sprintf(buf, "%lu",
+ (unsigned long) mkt);
+ pt = _add(buf, pt, ptlim, modifier);
+ }
+ continue;
+ case 'T':
+ pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 't':
+ pt = _add("\t", pt, ptlim, modifier);
+ continue;
+ case 'U':
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ t->tm_wday) / DAYSPERWEEK,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'u':
+ /*
+ ** From Arnold Robbins' strftime version 3.0:
+ ** "ISO 8601: Weekday as a decimal number
+ ** [1 (Monday) - 7]"
+ ** (ado, 1993-05-24)
+ */
+ pt = _conv((t->tm_wday == 0) ?
+ DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
+ continue;
+ case 'V': /* ISO 8601 week number */
+ case 'G': /* ISO 8601 year (four digits) */
+ case 'g': /* ISO 8601 year (two digits) */
+/*
+** From Arnold Robbins' strftime version 3.0: "the week number of the
+** year (the first Monday as the first day of week 1) as a decimal number
+** (01-53)."
+** (ado, 1993-05-24)
+**
+** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+** "Week 01 of a year is per definition the first week which has the
+** Thursday in this year, which is equivalent to the week which contains
+** the fourth day of January. In other words, the first week of a new year
+** is the week which has the majority of its days in the new year. Week 01
+** might also contain days from the previous year and the week before week
+** 01 of a year is the last week (52 or 53) of the previous year even if
+** it contains days from the new year. A week starts with Monday (day 1)
+** and ends with Sunday (day 7). For example, the first week of the year
+** 1997 lasts from 1996-12-30 to 1997-01-05..."
+** (ado, 1996-01-02)
+*/
+ {
+ int year;
+ int base;
+ int yday;
+ int wday;
+ int w;
+
+ year = t->tm_year;
+ base = TM_YEAR_BASE;
+ yday = t->tm_yday;
+ wday = t->tm_wday;
+ for ( ; ; ) {
+ int len;
+ int bot;
+ int top;
+
+ len = isleap_sum(year, base) ?
+ DAYSPERLYEAR :
+ DAYSPERNYEAR;
+ /*
+ ** What yday (-3 ... 3) does
+ ** the ISO year begin on?
+ */
+ bot = ((yday + 11 - wday) %
+ DAYSPERWEEK) - 3;
+ /*
+ ** What yday does the NEXT
+ ** ISO year begin on?
+ */
+ top = bot -
+ (len % DAYSPERWEEK);
+ if (top < -3)
+ top += DAYSPERWEEK;
+ top += len;
+ if (yday >= top) {
+ ++base;
+ w = 1;
+ break;
+ }
+ if (yday >= bot) {
+ w = 1 + ((yday - bot) /
+ DAYSPERWEEK);
+ break;
+ }
+ --base;
+ yday += isleap_sum(year, base) ?
+ DAYSPERLYEAR :
+ DAYSPERNYEAR;
+ }
+#ifdef XPG4_1994_04_09
+ if ((w == 52 &&
+ t->tm_mon == TM_JANUARY) ||
+ (w == 1 &&
+ t->tm_mon == TM_DECEMBER))
+ w = 53;
+#endif /* defined XPG4_1994_04_09 */
+ if (*format == 'V')
+ pt = _conv(w,
+ getformat(modifier,
+ "%02d",
+ "%2d",
+ "%d",
+ "%02d"),
+ pt, ptlim);
+ else if (*format == 'g') {
+ *warnp = IN_ALL;
+ pt = _yconv(year, base, 0, 1,
+ pt, ptlim, modifier);
+ } else pt = _yconv(year, base, 1, 1,
+ pt, ptlim, modifier);
+ }
+ continue;
+ case 'v':
+ /*
+ ** From Arnold Robbins' strftime version 3.0:
+ ** "date as dd-bbb-YYYY"
+ ** (ado, 1993-05-24)
+ */
+ pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'W':
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ (t->tm_wday ?
+ (t->tm_wday - 1) :
+ (DAYSPERWEEK - 1))) / DAYSPERWEEK,
+ getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ continue;
+ case 'w':
+ pt = _conv(t->tm_wday, "%d", pt, ptlim);
+ continue;
+ case 'X':
+ pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
+ continue;
+ case 'x':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'y':
+ *warnp = IN_ALL;
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+ pt, ptlim, modifier);
+ continue;
+ case 'Y':
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+ pt, ptlim, modifier);
+ continue;
+ case 'Z':
+#ifdef TM_ZONE
+ if (t->TM_ZONE != NULL)
+ pt = _add(t->TM_ZONE, pt, ptlim,
+ modifier);
+ else
+#endif /* defined TM_ZONE */
+ if (t->tm_isdst >= 0)
+ pt = _add(tzname[t->tm_isdst != 0],
+ pt, ptlim, modifier);
+ /*
+ ** C99 says that %Z must be replaced by the
+ ** empty string if the time zone is not
+ ** determinable.
+ */
+ continue;
+ case 'z':
+ {
+ int diff;
+ char const * sign;
+
+ if (t->tm_isdst < 0)
+ continue;
+#ifdef TM_GMTOFF
+ diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+ /*
+ ** C99 says that the UTC offset must
+ ** be computed by looking only at
+ ** tm_isdst. This requirement is
+ ** incorrect, since it means the code
+ ** must rely on magic (in this case
+ ** altzone and timezone), and the
+ ** magic might not have the correct
+ ** offset. Doing things correctly is
+ ** tricky and requires disobeying C99;
+ ** see GNU C strftime for details.
+ ** For now, punt and conform to the
+ ** standard, even though it's incorrect.
+ **
+ ** C99 says that %z must be replaced by the
+ ** empty string if the time zone is not
+ ** determinable, so output nothing if the
+ ** appropriate variables are not available.
+ */
+ if (t->tm_isdst == 0)
+#ifdef USG_COMPAT
+ diff = -timezone;
+#else /* !defined USG_COMPAT */
+ continue;
+#endif /* !defined USG_COMPAT */
+ else
+#ifdef ALTZONE
+ diff = -altzone;
+#else /* !defined ALTZONE */
+ continue;
+#endif /* !defined ALTZONE */
+#endif /* !defined TM_GMTOFF */
+ if (diff < 0) {
+ sign = "-";
+ diff = -diff;
+ } else sign = "+";
+ pt = _add(sign, pt, ptlim, modifier);
+ diff /= SECSPERMIN;
+ diff = (diff / MINSPERHOUR) * 100 +
+ (diff % MINSPERHOUR);
+ pt = _conv(diff,
+ getformat(modifier, "%04d",
+ "%4d", "%d", "%04d"),
+ pt, ptlim);
+ }
+ continue;
+ case '+':
+ pt = _fmt(Locale->date_fmt, t, pt, ptlim,
+ warnp, Locale);
+ continue;
+ case '%':
+ /*
+ ** X311J/88-090 (4.12.3.5): if conversion char is
+ ** undefined, behavior is undefined. Print out the
+ ** character itself as printf(3) also does.
+ */
+ default:
+ break;
+ }
+ }
+ if (pt == ptlim)
+ break;
+ *pt++ = *format;
+ }
+ return pt;
+}
+
+static char *
+_conv(n, format, pt, ptlim)
+const int n;
+const char * const format;
+char * const pt;
+const char * const ptlim;
+{
+ char buf[INT_STRLEN_MAXIMUM(int) + 1];
+
+ (void) sprintf(buf, format, n);
+ return _add(buf, pt, ptlim, 0);
+}
+
+static char *
+_add(str, pt, ptlim, modifier)
+const char * str;
+char * pt;
+const char * const ptlim;
+int modifier;
+{
+ int c;
+
+ switch (modifier) {
+ case FORCE_LOWER_CASE:
+ while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
+ ++pt;
+ }
+ break;
+
+ case '^':
+ while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
+ ++pt;
+ }
+ break;
+
+ case '#':
+ while (pt < ptlim && (c = *str++) != '\0') {
+ if (isupper(c)) {
+ c = tolower(c);
+ } else if (islower(c)) {
+ c = toupper(c);
+ }
+ *pt = c;
+ ++pt;
+ }
+
+ break;
+
+ default:
+ while (pt < ptlim && (*pt = *str++) != '\0') {
+ ++pt;
+ }
+ }
+
+ return pt;
+}
+
+/*
+** POSIX and the C Standard are unclear or inconsistent about
+** what %C and %y do if the year is negative or exceeds 9999.
+** Use the convention that %C concatenated with %y yields the
+** same output as %Y, and that %Y contains at least 4 bytes,
+** with more only if necessary.
+*/
+
+static char *
+_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
+const int a;
+const int b;
+const int convert_top;
+const int convert_yy;
+char * pt;
+const char * const ptlim;
+int modifier;
+{
+ register int lead;
+ register int trail;
+
+#define DIVISOR 100
+ trail = a % DIVISOR + b % DIVISOR;
+ lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (convert_top) {
+ if (lead == 0 && trail < 0)
+ pt = _add("-0", pt, ptlim, modifier);
+ else pt = _conv(lead, getformat(modifier, "%02d",
+ "%2d", "%d", "%02d"),
+ pt, ptlim);
+ }
+ if (convert_yy)
+ pt = _conv(((trail < 0) ? -trail : trail),
+ getformat(modifier, "%02d", "%2d", "%d", "%02d"),
+ pt, ptlim);
+ return pt;
+}
+
+#ifdef LOCALE_HOME
+static struct lc_time_T *
+_loc P((void))
+{
+ static const char locale_home[] = LOCALE_HOME;
+ static const char lc_time[] = "LC_TIME";
+ static char * locale_buf;
+
+ int fd;
+ int oldsun; /* "...ain't got nothin' to do..." */
+ char * lbuf;
+ char * name;
+ char * p;
+ const char ** ap;
+ const char * plim;
+ char filename[FILENAME_MAX];
+ struct stat st;
+ size_t namesize;
+ size_t bufsize;
+
+ /*
+ ** Use localebuf.mon[0] to signal whether locale is already set up.
+ */
+ if (localebuf.mon[0])
+ return &localebuf;
+ name = setlocale(LC_TIME, (char *) NULL);
+ if (name == NULL || *name == '\0')
+ goto no_locale;
+ /*
+ ** If the locale name is the same as our cache, use the cache.
+ */
+ lbuf = locale_buf;
+ if (lbuf != NULL && strcmp(name, lbuf) == 0) {
+ p = lbuf;
+ for (ap = (const char **) &localebuf;
+ ap < (const char **) (&localebuf + 1);
+ ++ap)
+ *ap = p += strlen(p) + 1;
+ return &localebuf;
+ }
+ /*
+ ** Slurp the locale file into the cache.
+ */
+ namesize = strlen(name) + 1;
+ if (sizeof filename <
+ ((sizeof locale_home) + namesize + (sizeof lc_time)))
+ goto no_locale;
+ oldsun = 0;
+ (void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ /*
+ ** Old Sun systems have a different naming and data convention.
+ */
+ oldsun = 1;
+ (void) sprintf(filename, "%s/%s/%s", locale_home,
+ lc_time, name);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto no_locale;
+ }
+ if (fstat(fd, &st) != 0)
+ goto bad_locale;
+ if (st.st_size <= 0)
+ goto bad_locale;
+ bufsize = namesize + st.st_size;
+ locale_buf = NULL;
+ lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
+ if (lbuf == NULL)
+ goto bad_locale;
+ (void) strcpy(lbuf, name);
+ p = lbuf + namesize;
+ plim = p + st.st_size;
+ if (read(fd, p, (size_t) st.st_size) != st.st_size)
+ goto bad_lbuf;
+ if (close(fd) != 0)
+ goto bad_lbuf;
+ /*
+ ** Parse the locale file into localebuf.
+ */
+ if (plim[-1] != '\n')
+ goto bad_lbuf;
+ for (ap = (const char **) &localebuf;
+ ap < (const char **) (&localebuf + 1);
+ ++ap) {
+ if (p == plim)
+ goto bad_lbuf;
+ *ap = p;
+ while (*p != '\n')
+ ++p;
+ *p++ = '\0';
+ }
+ if (oldsun) {
+ /*
+ ** SunOS 4 used an obsolescent format; see localdtconv(3).
+ ** c_fmt had the ``short format for dates and times together''
+ ** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
+ ** date_fmt had the ``long format for dates''
+ ** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
+ ** Discard the latter in favor of the former.
+ */
+ localebuf.date_fmt = localebuf.c_fmt;
+ }
+ /*
+ ** Record the successful parse in the cache.
+ */
+ locale_buf = lbuf;
+
+ return &localebuf;
+
+bad_lbuf:
+ free(lbuf);
+bad_locale:
+ (void) close(fd);
+no_locale:
+ localebuf = C_time_locale;
+ locale_buf = NULL;
+ return &localebuf;
+}
+#endif /* defined LOCALE_HOME */
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 97fe76dd3..ba9893351 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -181,6 +181,22 @@ int dhcp_stop(const char *interface)
return 0;
}
+/**
+ * Release the current DHCP client lease.
+ */
+int dhcp_release_lease(const char *interface)
+{
+ const char *ctrl_prop = "ctl.stop";
+ const char *desired_status = "stopped";
+
+ /* Stop the daemon and wait until it's reported to be stopped */
+ property_set(ctrl_prop, DAEMON_NAME);
+ if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
char *dhcp_get_errmsg() {
return errmsg;
}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index a8e5ee4eb..6edc56fec 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -85,3 +85,6 @@ ifeq ($(TARGET_ARCH),arm)
LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6
endif
include $(BUILD_STATIC_LIBRARY)
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 90c275e4b..1cd189c9f 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -151,6 +151,7 @@ int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
// Destination is zero (beware of logic ops)
}
+ int fbComponents = 0;
const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
for (int i=0 ; i<4 ; i++) {
const int mask = 1<<i;
@@ -176,9 +177,14 @@ int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
mBlending |= (info.blend ? mask : 0);
mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
+ fbComponents |= mCbFormat.c[i].h ? mask : 0;
}
-
+ mAllMasked = (mMasking == fbComponents);
+ if (mAllMasked) {
+ mDithering = 0;
+ }
+
fragment_parts_t parts;
// ------------------------------------------------------------------------
@@ -226,8 +232,10 @@ int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
build_textures(parts, regs);
}
- if ((blending & (FACTOR_DST|BLEND_DST)) || mMasking ||
- (mLogicOp & LOGIC_OP_DST)) {
+ if ((blending & (FACTOR_DST|BLEND_DST)) ||
+ (mMasking && !mAllMasked) ||
+ (mLogicOp & LOGIC_OP_DST))
+ {
// blending / logic_op / masking need the framebuffer
mDstPixel.setTo(regs.obtain(), &mCbFormat);
@@ -284,14 +292,16 @@ int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
pixel = mDstPixel;
}
- // logic operation
- build_logic_op(pixel, regs);
-
- // masking
- build_masking(pixel, regs);
-
- comment("store");
- store(parts.cbPtr, pixel, WRITE_BACK);
+ if (!mAllMasked) {
+ // logic operation
+ build_logic_op(pixel, regs);
+
+ // masking
+ build_masking(pixel, regs);
+
+ comment("store");
+ store(parts.cbPtr, pixel, WRITE_BACK);
+ }
}
if (registerFile().status())
@@ -322,7 +332,9 @@ int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
build_smooth_shade(parts);
build_iterate_z(parts);
build_iterate_f(parts);
- ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+ if (!mAllMasked) {
+ ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+ }
SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
B(PL, "fragment_loop");
epilog(registerFile().touched());
@@ -370,16 +382,18 @@ void GGLAssembler::build_scanline_prolog(
MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
}
- // compute dst ptr
- comment("compute color-buffer pointer");
- const int cb_bits = mCbFormat.size*8;
- int Rs = scratches.obtain();
- parts.cbPtr.setTo(obtainReg(), cb_bits);
- CONTEXT_LOAD(Rs, state.buffers.color.stride);
- CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
- SMLABB(AL, Rs, Ry, Rs, Rx); // Rs = Rx + Ry*Rs
- base_offset(parts.cbPtr, parts.cbPtr, Rs);
- scratches.recycle(Rs);
+ if (!mAllMasked) {
+ // compute dst ptr
+ comment("compute color-buffer pointer");
+ const int cb_bits = mCbFormat.size*8;
+ int Rs = scratches.obtain();
+ parts.cbPtr.setTo(obtainReg(), cb_bits);
+ CONTEXT_LOAD(Rs, state.buffers.color.stride);
+ CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
+ SMLABB(AL, Rs, Ry, Rs, Rx); // Rs = Rx + Ry*Rs
+ base_offset(parts.cbPtr, parts.cbPtr, Rs);
+ scratches.recycle(Rs);
+ }
// init fog
const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
@@ -904,8 +918,9 @@ void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits)
void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
{
- if (!mMasking)
+ if (!mMasking || mAllMasked) {
return;
+ }
comment("color mask");
@@ -928,7 +943,7 @@ void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
// There is no need to clear the masked components of the source
// (unless we applied a logic op), because they're already zeroed
- // by contruction (masked components are not computed)
+ // by construction (masked components are not computed)
if (mLogicOp) {
const needs_t& needs = mBuilderContext.needs;
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index ccaf43d3a..d1d29f0b0 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -363,6 +363,10 @@ private:
const component_t& incoming,
const pixel_t& texel, int component, int tmu);
+ void add( component_t& dest,
+ const component_t& incoming,
+ const pixel_t& texel, int component);
+
// load/store stuff
void store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
void load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
@@ -517,6 +521,7 @@ private:
component_info_t mInfo[4];
int mBlending;
int mMasking;
+ int mAllMasked;
int mLogicOp;
int mAlphaTest;
int mAA;
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index 6d3b28201..f10217b74 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -50,6 +50,12 @@ void GGLAssembler::build_fog(
integer_t factor(scratches.obtain(), 16, CORRUPTIBLE);
CONTEXT_LOAD(factor.reg, generated_vars.f);
+ // clamp fog factor (TODO: see if there is a way to guarantee
+ // we won't overflow, when setting the iterators)
+ BIC(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, ASR, 31));
+ CMP(AL, factor.reg, imm( 0x10000 ));
+ MOV(HS, 0, factor.reg, imm( 0x10000 ));
+
build_blendFOneMinusF(temp, factor, fragment, fogColor);
}
}
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index 514ce073e..93c582579 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -168,7 +168,7 @@ void GGLAssembler::expand(integer_t& d, const component_t& s, int dbits)
void GGLAssembler::expand(component_t& d, const component_t& s, int dbits)
{
integer_t r(d.reg, 32, d.flags);
- expand(r, d, dbits);
+ expand(r, s, dbits);
d = component_t(r);
}
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 269b6c003..90e658407 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -1000,6 +1000,9 @@ void GGLAssembler::build_texture_environment(
case GGL_BLEND:
blend(fragment, incoming, texel, component, i);
break;
+ case GGL_ADD:
+ add(fragment, incoming, texel, component);
+ break;
}
}
}
@@ -1202,6 +1205,46 @@ void GGLAssembler::blend(
build_blendOneMinusFF(dest, factor, incomingNorm, color);
}
+void GGLAssembler::add(
+ component_t& dest,
+ const component_t& incoming,
+ const pixel_t& incomingTexel, int component)
+{
+ // RGBA:
+ // Cv = Cf + Ct;
+ Scratch locals(registerFile());
+
+ component_t incomingTemp(incoming);
+
+ // use "dest" as a temporary for extracting the texel, unless "dest"
+ // overlaps "incoming".
+ integer_t texel(dest.reg, 32, CORRUPTIBLE);
+ if (dest.reg == incomingTemp.reg)
+ texel.reg = locals.obtain();
+ extract(texel, incomingTexel, component);
+
+ if (texel.s < incomingTemp.size()) {
+ expand(texel, texel, incomingTemp.size());
+ } else if (texel.s > incomingTemp.size()) {
+ if (incomingTemp.flags & CORRUPTIBLE) {
+ expand(incomingTemp, incomingTemp, texel.s);
+ } else {
+ incomingTemp.reg = locals.obtain();
+ expand(incomingTemp, incoming, texel.s);
+ }
+ }
+
+ if (incomingTemp.l) {
+ ADD(AL, 0, dest.reg, texel.reg,
+ reg_imm(incomingTemp.reg, LSR, incomingTemp.l));
+ } else {
+ ADD(AL, 0, dest.reg, texel.reg, incomingTemp.reg);
+ }
+ dest.l = 0;
+ dest.h = texel.size();
+ component_sat(dest);
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp
index c77eadaba..cbbd91a0e 100644
--- a/libpixelflinger/format.cpp
+++ b/libpixelflinger/format.cpp
@@ -21,13 +21,13 @@
namespace android {
static GGLFormat const gPixelFormatInfos[] =
-{
+{ // Alpha Red Green Blue
{ 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
{ 4, 32, {{32,24, 8, 0, 16, 8, 24,16 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_8888
{ 4, 24, {{ 0, 0, 8, 0, 16, 8, 24,16 }}, GGL_RGB }, // PIXEL_FORMAT_RGBX_8888
{ 3, 24, {{ 0, 0, 8, 0, 16, 8, 24,16 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_888
{ 2, 16, {{ 0, 0, 16,11, 11, 5, 5, 0 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_565
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
+ { 4, 32, {{32,24, 24,16, 16, 8, 8, 0 }}, GGL_RGBA }, // PIXEL_FORMAT_BGRA_8888
{ 2, 16, {{ 1, 0, 16,11, 11, 6, 6, 1 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_5551
{ 2, 16, {{ 4, 0, 16,12, 12, 8, 8, 4 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_4444
{ 1, 8, {{ 8, 0, 0, 0, 0, 0, 0, 0 }}, GGL_ALPHA}, // PIXEL_FORMAT_A8
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index d24c98805..75b668d37 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -55,9 +55,11 @@
# define ANDROID_ARM_CODEGEN 0
#endif
-
#define DEBUG__CODEGEN_ONLY 0
+
+#define ASSEMBLY_SCRATCH_SIZE 2048
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -247,7 +249,8 @@ static void pick_scanline(context_t* c)
sp<Assembly> assembly = gCodeCache.lookup(key);
if (assembly == 0) {
// create a new assembly region
- sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs, 1024);
+ sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs,
+ ASSEMBLY_SCRATCH_SIZE);
// initialize our assembler
GGLAssembler assembler( new ARMAssembler(a) );
//GGLAssembler assembler(
@@ -676,6 +679,12 @@ void scanline(context_t* c)
Cf = ((((1<<st) - factor) * Cf) + Ct*Cc)>>st;
}
break;
+ case GGL_ADD:
+ if (st) {
+ rescale(Cf, sf, Ct, st);
+ Cf += Ct;
+ }
+ break;
}
}
}
@@ -1473,7 +1482,7 @@ extern "C" void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t
needs.p = p;
needs.t[0] = t0;
needs.t[1] = t1;
- sp<ScanlineAssembly> a(new ScanlineAssembly(needs, 1024));
+ sp<ScanlineAssembly> a(new ScanlineAssembly(needs, ASSEMBLY_SCRATCH_SIZE));
GGLAssembler assembler( new ARMAssembler(a) );
int err = assembler.scanline(needs, (context_t*)c);
if (err != 0) {
diff --git a/libpixelflinger/tests/Android.mk b/libpixelflinger/tests/Android.mk
new file mode 100644
index 000000000..65711611c
--- /dev/null
+++ b/libpixelflinger/tests/Android.mk
@@ -0,0 +1 @@
+include $(all-subdir-makefiles)
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
new file mode 100644
index 000000000..1bc421487
--- /dev/null
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ codegen.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libpixelflinger
+
+LOCAL_MODULE:= test-opengl-codegen
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
new file mode 100644
index 000000000..18658881b
--- /dev/null
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdint.h>
+
+extern "C" void ggl_test_codegen(
+ uint32_t n, uint32_t p, uint32_t t0, uint32_t t1);
+
+
+int main(int argc, char** argv)
+{
+ if (argc != 2) {
+ printf("usage: %s 00000117:03454504_00001501_00000000\n", argv[0]);
+ return 0;
+ }
+ uint32_t n;
+ uint32_t p;
+ uint32_t t0;
+ uint32_t t1;
+ sscanf(argv[1], "%08x:%08x_%08x_%08x", &p, &n, &t0, &t1);
+ ggl_test_codegen(n, p, t0, t1);
+ return 0;
+}
diff --git a/logcat/event-log-tags b/logcat/event-log-tags
index 3ee5f8e64..3d977a5e5 100644
--- a/logcat/event-log-tags
+++ b/logcat/event-log-tags
@@ -244,8 +244,8 @@
50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3)
50001 menu_opened (Menu type where 0 is options and 1 is context|1|5)
# Connectivity state changed:
-# [31-11] Reserved for future use
-# [10-9] Mobile network connection type (as defined by the TelephonyManager)
+# [31-13] Reserved for future use
+# [12- 9] Network subtype (for mobile network, as defined by TelephonyManager)
# [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
# [ 2- 0] Network type (as defined by ConnectivityManager)
50020 connectivity_state_changed (custom|1|5)
@@ -271,8 +271,9 @@
50024 wifi_interface_configuration_state_changed (IP_configuration|1|5)
# Wi-Fi supplicant connection state changed:
-# [31- 1] Reserved for future use
-# [ 0- 0] Connected to supplicant (1) or disconnected from supplicant (0)
+# [31- 2] Reserved for future use
+# [ 1- 0] Connected to supplicant (1) or disconnected from supplicant (0),
+# or supplicant died (2)
50025 wifi_supplicant_connection_state_changed (connected|1|5)
# PDP Context has a bad DNS address
@@ -291,6 +292,17 @@
# Reregister to data network - timed out with no incoming packets.
50104 pdp_reregister_network (out_packet_count|1|1)
+# PDP Setup failures
+50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5)
+
+# Call drops
+50106 call_drop (cause|1|5), (cid|1|5), (network_type|1|5)
+
+# Data network registration failed after successful voice registration
+50107 data_network_registration_fail (op_numeric|1|5), (cid|1|5)
+
+# Suspicious status of data connection while radio poweroff
+50108 data_network_status_on_radio_off (dc_state|3), (enable|1|5)
# Do not change these names without updating tag in:
#//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index c7a253460..f00bfbf3d 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -21,7 +21,9 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include "private/android_filesystem_config.h"
#include "cutils/log.h"
void fatal(const char *msg) {
@@ -32,48 +34,74 @@ void fatal(const char *msg) {
void usage() {
fatal(
- "Usage: logwrapper BINARY [ARGS ...]\n"
+ "Usage: logwrapper [-x] BINARY [ARGS ...]\n"
"\n"
"Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
"the Android logging system. Tag is set to BINARY, priority is\n"
- "always LOG_INFO.\n");
+ "always LOG_INFO.\n"
+ "\n"
+ "-x: Causes logwrapper to SIGSEGV when BINARY terminates\n"
+ " fault address is set to the status of wait()\n");
}
-void parent(const char *tag, int parent_read) {
+void parent(const char *tag, int seg_fault_on_exit, int parent_read) {
int status;
- char buffer[1024];
+ char buffer[4096];
int a = 0; // start index of unprocessed data
int b = 0; // end index of unprocessed data
int sz;
- while ((sz = read(parent_read, &buffer[b], 1023 - b)) > 0) {
+ while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
+
+ sz += b;
// Log one line at a time
- for (b = a; b < sz; b++) {
- if (buffer[b] == '\n') {
+ for (b = 0; b < sz; b++) {
+ if (buffer[b] == '\r') {
+ buffer[b] = '\0';
+ } else if (buffer[b] == '\n') {
buffer[b] = '\0';
LOG(LOG_INFO, tag, &buffer[a]);
a = b + 1;
}
}
- if (a == 0 && b == 1023) {
+ if (a == 0 && b == sizeof(buffer) - 1) {
// buffer is full, flush
buffer[b] = '\0';
LOG(LOG_INFO, tag, &buffer[a]);
b = 0;
- } else {
+ } else if (a != b) {
// Keep left-overs
- b = sz - a;
+ b -= a;
memmove(buffer, &buffer[a], b);
a = 0;
+ } else {
+ a = 0;
+ b = 0;
}
+
}
// Flush remaining data
if (a != b) {
buffer[b] = '\0';
LOG(LOG_INFO, tag, &buffer[a]);
}
- wait(&status); // Wait for child
+ status = 0xAAAA;
+ if (wait(&status) != -1) { // Wait for child
+ if (WIFEXITED(status))
+ LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
+ WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
+ WTERMSIG(status));
+ else if (WIFSTOPPED(status))
+ LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
+ WSTOPSIG(status));
+ } else
+ LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
+ strerror(errno), errno);
+ if (seg_fault_on_exit)
+ *(int *)status = 0; // causes SIGSEGV with fault_address = status
}
void child(int argc, char* argv[]) {
@@ -91,35 +119,62 @@ void child(int argc, char* argv[]) {
int main(int argc, char* argv[]) {
pid_t pid;
+ int seg_fault_on_exit = 0;
+
+ int parent_ptty;
+ int child_ptty;
+ char *child_devname = NULL;
- int pipe_fds[2];
- int *parent_read = &pipe_fds[0];
- int *child_write = &pipe_fds[1];
+ if (argc < 2) {
+ usage();
+ }
+
+ if (strncmp(argv[1], "-d", 2) == 0) {
+ seg_fault_on_exit = 1;
+ argc--;
+ argv++;
+ }
if (argc < 2) {
usage();
}
- if (pipe(pipe_fds) < 0) {
- fatal("Cannot create pipe\n");
+ /* Use ptty instead of socketpair so that STDOUT is not buffered */
+ parent_ptty = open("/dev/ptmx", O_RDWR);
+ if (parent_ptty < 0) {
+ fatal("Cannot create parent ptty\n");
+ }
+
+ if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
+ ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+ fatal("Problem with /dev/ptmx\n");
}
pid = fork();
if (pid < 0) {
fatal("Failed to fork\n");
} else if (pid == 0) {
+ child_ptty = open(child_devname, O_RDWR);
+ if (child_ptty < 0) {
+ fatal("Problem with child ptty\n");
+ }
+
// redirect stdout and stderr
- close(*parent_read);
- dup2(*child_write, 1);
- dup2(*child_write, 2);
- close(*child_write);
+ close(parent_ptty);
+ dup2(child_ptty, 1);
+ dup2(child_ptty, 2);
+ close(child_ptty);
child(argc - 1, &argv[1]);
} else {
- close(*child_write);
+ // switch user and group to "log"
+ // this may fail if we are not root,
+ // but in that case switching user/group is unnecessary
+ setgid(AID_LOG);
+ setuid(AID_LOG);
- parent(argv[1], *parent_read);
+ parent(argv[1], seg_fault_on_exit, parent_ptty);
}
return 0;
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
index e44bd99a0..a579de0b6 100644
--- a/mkbootimg/Android.mk
+++ b/mkbootimg/Android.mk
@@ -8,4 +8,4 @@ LOCAL_MODULE := mkbootimg
include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,user userdebug droid,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
diff --git a/mountd/ASEC.c b/mountd/ASEC.c
new file mode 100644
index 000000000..3d8e50e0a
--- /dev/null
+++ b/mountd/ASEC.c
@@ -0,0 +1,770 @@
+/*
+ * 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.
+ */
+
+/*
+** Android Secure External Cache
+*/
+
+#include "mountd.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <linux/loop.h>
+
+#include <cutils/properties.h>
+#include <cutils/misc.h>
+
+#include "ASEC.h"
+#include "dm-ioctl.h"
+
+extern int init_module(void *, unsigned long, const char *);
+extern int delete_module(const char *, unsigned int);
+
+struct asec_context
+{
+ char *name; // Device mapper volume name
+ char *srcPath; // Path to the source (original) mount
+ char *backingFile; // Name of the image file
+ unsigned int sectors; // Number of sectors
+ char *dstPath; // Destination mount point
+ char *crypt; // Crypt options
+
+ boolean needs_format;
+ boolean started;
+ int cacheFd;
+ int lo_num;
+ int dm_num;
+ unsigned char key[16];
+};
+
+static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher",
+ "cryptomgr", "dm_crypt", "jbd",
+ "twofish_common", "twofish", "cbc",
+ "mbcache", "ext3",
+ NULL };
+static const char KEY_PATH[] = "/data/system/asec.key";
+static const char MODULE_PATH[] = "/system/lib/modules";
+static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
+static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
+
+boolean AsecIsStarted(void *Handle)
+{
+ struct asec_context *ctx = (struct asec_context *) Handle;
+
+ return ctx->started;
+}
+
+const char *AsecMountPoint(void *Handle)
+{
+ struct asec_context *ctx = (struct asec_context *) Handle;
+
+ return ctx->dstPath;
+}
+
+static boolean AsecIsEnabled()
+{
+ char value[PROPERTY_VALUE_MAX];
+ int enabled;
+
+ property_get(ASEC_ENABLED, value, "0");
+
+ if (atoi(value) == 1)
+ return true;
+ return false;
+}
+
+void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
+ const char *Size, const char *DstPath, const char *Crypt)
+{
+ struct asec_context *ctx;
+
+ LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
+ Name, SrcPath, BackingFile, Size, DstPath, Crypt);
+
+ if (!AsecIsEnabled()) {
+ LOG_ERROR("AsecInit(): Disabled\n");
+ return NULL;
+ }
+
+ if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
+ LOG_ERROR("AsecInit(): Invalid arguments\n");
+ return NULL;
+ }
+
+ if (!(ctx = malloc(sizeof(struct asec_context)))) {
+ LOG_ERROR("AsecInit(): Out of memory\n");
+ return NULL;
+ }
+
+ memset(ctx, 0, sizeof(struct asec_context));
+ ctx->name = strdup(Name);
+ ctx->srcPath = strdup(SrcPath);
+ ctx->backingFile = strdup(BackingFile);
+ ctx->sectors = atoi(Size);
+ ctx->dstPath = strdup(DstPath);
+ ctx->crypt = strdup(Crypt);
+ return ctx;
+}
+
+void AsecDeinit(void *Handle)
+{
+ struct asec_context *ctx = (struct asec_context *) Handle;
+
+ free(ctx->name);
+ free(ctx->srcPath);
+ free(ctx->backingFile);
+ free(ctx->dstPath);
+ free(ctx->crypt);
+
+ free(ctx);
+}
+
+static int AsecLoadModules()
+{
+ int i;
+
+ for (i = 0; MODULES[i] != NULL; i++) {
+ const char *moduleName = MODULES[i];
+ char moduleFile[255];
+ int rc = 0;
+ void *module;
+ unsigned int size;
+
+ sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
+ module = load_file(moduleFile, &size);
+ if (!module) {
+ LOG_ERROR("Failed to load module %s\n", moduleFile);
+ return -1;
+ }
+
+ rc = init_module(module, size, "");
+ free(module);
+ if (rc && errno != EEXIST) {
+ LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+static int AsecUnloadModules()
+{
+ int i, j, rc;
+
+ for (i = 0; MODULES[i] != NULL; i++);
+
+ for (j = (i - 1); j >= 0; j--) {
+ const char *moduleName = MODULES[j];
+ int maxretry = 10;
+ while(maxretry-- > 0) {
+ rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
+ if (rc < 0 && errno == EAGAIN)
+ usleep(500000);
+ else
+ break;
+ }
+ if (rc != 0) {
+ LOG_ERROR("Failed to unload module %s\n", moduleName);
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+static int AsecGenerateKey(struct asec_context *ctx)
+{
+ LOG_ASEC("AsecGenerateKey():\n");
+
+ memset((void *) ctx->key, 0x69, sizeof(ctx->key));
+ return 0;
+}
+
+static int AsecLoadGenerateKey(struct asec_context *ctx)
+{
+ int fd;
+ int rc = 0;
+
+ if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
+ LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
+ return -errno;
+ }
+
+ if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
+ LOG_ASEC("Generating key\n");
+ if ((rc = AsecGenerateKey(ctx)) < 0) {
+ LOG_ERROR("Error generating key (%d)\n", rc);
+ goto out;
+ }
+ if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
+ LOG_ERROR("Error writing keyfile (%d)\n", errno);
+ rc = -1;
+ goto out;
+ }
+ }
+
+ out:
+ close (fd);
+ return rc;
+}
+
+static int AsecFormatFilesystem(struct asec_context *ctx)
+{
+ char cmdline[255];
+ int rc;
+
+ sprintf(cmdline,
+ "%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
+ MKE2FS_PATH, ctx->name, ctx->dm_num);
+
+ LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
+ // XXX: PROTECT FROM VIKING KILLER
+ if ((rc = system(cmdline)) < 0) {
+ LOG_ERROR("Error executing format command (%d)\n", errno);
+ return -errno;
+ }
+
+ rc = WEXITSTATUS(rc);
+
+ if (!rc) {
+ LOG_ASEC("Format completed\n");
+ } else {
+ LOG_ASEC("Format failed (%d)\n", rc);
+ }
+
+ return rc;
+}
+
+static int AsecCheckFilesystem(struct asec_context *ctx)
+{
+ char cmdline[255];
+ int rc;
+
+ sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
+
+ LOG_ASEC("Checking filesystem (%s)\n", cmdline);
+ // XXX: PROTECT FROM VIKING KILLER
+ if ((rc = system(cmdline)) < 0) {
+ LOG_ERROR("Error executing check command (%d)\n", errno);
+ return -errno;
+ }
+
+ rc = WEXITSTATUS(rc);
+
+ if (rc == 0) {
+ LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
+ } else if (rc == 1) {
+ LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
+ rc = 0;
+ } else if (rc == 2) {
+ LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
+ } else if (rc == 4) {
+ LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
+ } else if (rc == 8) {
+ LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
+ } else {
+ LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
+ }
+ return rc;
+}
+
+static int AsecOpenCreateCache(struct asec_context *ctx)
+{
+ char filepath[255];
+
+ sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
+
+ if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
+ if (errno == ENOENT) {
+ int rc = 0;
+
+ LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
+ if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
+ LOG_ERROR("Error creating cache (%d)\n", errno);
+ return -errno;
+ }
+ if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
+ LOG_ERROR("Error truncating cache (%d)\n", errno);
+ close(ctx->cacheFd);
+ unlink(filepath);
+ return -errno;
+ }
+ LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
+ close(ctx->cacheFd); // creat() is WRONLY
+
+ if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
+ LOG_ERROR("Error opening cache file (%d)\n", errno);
+ close(ctx->cacheFd);
+ unlink(filepath);
+ return -errno;
+ }
+
+ ctx->needs_format = 1;
+ } else
+ return -errno;
+ } else {
+ struct stat stat_buf;
+
+ if (fstat(ctx->cacheFd, &stat_buf) < 0) {
+ LOG_ERROR("Failed to fstat cache (%d)\n", errno);
+ close(ctx->cacheFd);
+ return -errno;
+ }
+ if (stat_buf.st_size != ctx->sectors * 512) {
+ LOG_ERROR("Cache size %lld != configured size %u\n",
+ stat_buf.st_size, ctx->sectors * 512);
+ }
+
+ // XXX: Verify volume label matches ctx->name
+ }
+
+ return 0;
+}
+
+static void AsecCloseCache(struct asec_context *ctx)
+{
+ close(ctx->cacheFd);
+}
+
+static void *_align(void *ptr, unsigned int a)
+{
+ register unsigned long agn = --a;
+
+ return (void *) (((unsigned long) ptr + agn) & ~agn);
+}
+
+static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
+{
+ void *buffer;
+ void *p;
+ const size_t min_size = 16 * 1024;
+ size_t len = sizeof(struct dm_ioctl);
+ struct dm_ioctl *io;
+ struct dm_target_spec *tgt;
+ int i;
+ char params[1024];
+ char key[80];
+
+ key[0] = '\0';
+
+ for (i = 0; i < (int) sizeof(ctx->key); i++) {
+ char tmp[8];
+
+ sprintf(tmp, "%02x", ctx->key[i]);
+ strcat(key, tmp);
+ }
+
+ // XXX: Handle ctx->crypt
+ sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
+
+ if (len < min_size)
+ len = min_size;
+
+ if (!(buffer = malloc(len))) {
+ LOG_ERROR("Unable to allocate memory\n");
+ return NULL;
+ }
+
+ memset(buffer, 0, len);
+ io = buffer;
+ tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+
+ io->version[0] = 4;
+ io->version[1] = 0;
+ io->version[2] = 0;
+
+ io->data_size = len;
+ io->data_start = sizeof(struct dm_ioctl);
+
+ io->flags = flags;
+ io->dev = 0;
+
+ io->target_count = 1;
+ io->event_nr = 1;
+ strncpy(io->name, ctx->name, sizeof(io->name));
+
+ tgt->status = 0;
+ tgt->sector_start = 0;
+ tgt->length = ctx->sectors;
+ strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
+
+ p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+ strcpy((char *) p, params);
+ p+= strlen(params) + 1;
+
+ p = _align(p, 8);
+ tgt->next = p - buffer;
+
+ return io;
+}
+
+static int FindNextAvailableDm()
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ char path[255];
+ sprintf(path, "/dev/block/dm-%d", i);
+ if ((access(path, F_OK) < 0) && (errno == ENOENT))
+ return i;
+ }
+
+ LOG_ERROR("Out of device mapper numbers\n");
+ return -1;
+}
+
+static int AsecCreateDeviceMapping(struct asec_context *ctx)
+{
+ struct dm_ioctl *io;
+ int dmFd;
+ int rc = 0;
+
+ ctx->dm_num = FindNextAvailableDm();
+
+ if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
+ LOG_ERROR("Error opening device mapper (%d)\n", errno);
+ return -errno;
+ }
+
+ if (!(io = _dm_ioctl_setup(ctx, 0))) {
+ LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+ close(dmFd);
+ return -ENOMEM;
+ }
+
+ if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
+ LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
+ rc = -errno;
+ goto out_free;
+ }
+
+ free(io);
+
+ if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
+ LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+ rc = -ENOMEM;
+ goto out_nofree;
+ }
+
+ if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
+ LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
+ rc = -errno;
+ goto out_free;
+ }
+
+ free(io);
+
+ if (!(io = _dm_ioctl_setup(ctx, 0))) {
+ LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+ rc = -ENOMEM;
+ goto out_nofree;
+ }
+
+ if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
+ LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
+ rc = -errno;
+ goto out_free;
+ }
+
+out_free:
+ free (io);
+out_nofree:
+ close (dmFd);
+ return rc;
+}
+
+static int AsecDestroyDeviceMapping(struct asec_context *ctx)
+{
+ struct dm_ioctl *io;
+ int dmFd;
+ int rc = 0;
+
+ if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
+ LOG_ERROR("Error opening device mapper (%d)\n", errno);
+ return -errno;
+ }
+
+ if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
+ LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+ rc = -ENOMEM;
+ goto out_nofree;
+ }
+
+ if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
+ LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
+ rc = -errno;
+ goto out_free;
+ }
+
+out_free:
+ free (io);
+out_nofree:
+ close (dmFd);
+ return rc;
+}
+
+static int AsecMountCache(struct asec_context *ctx)
+{
+ int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
+ char devname[255];
+
+ if (access(ctx->dstPath, R_OK)) {
+ LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
+ return -errno;
+ }
+
+ sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
+
+ if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
+ LOG_ERROR("ASEC mount failed (%d)\n", errno);
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int AsecUnmountCache(struct asec_context *ctx)
+{
+ if (umount(ctx->dstPath)) {
+ if (errno == EBUSY) {
+ LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
+ } else {
+ LOG_ERROR("ASEC umount failed (%d)\n", errno);
+ }
+ return -errno;
+ }
+ LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
+ return 0;
+}
+
+static int FindNextAvailableLoop()
+{
+ int i;
+
+ for (i = 0; i < MAX_LOOP; i++) {
+ struct loop_info info;
+ char devname[255];
+ int fd;
+
+ sprintf(devname, "/dev/block/loop%d", i);
+
+ if ((fd = open(devname, O_RDONLY)) < 0) {
+ LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
+ return -errno;
+ }
+
+ if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
+ close(fd);
+
+ if (errno == ENXIO)
+ return i;
+
+ LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
+ return -errno;
+ }
+ close(fd);
+ }
+ return -ENXIO;
+}
+
+static int AsecCreateLoop(struct asec_context *ctx)
+{
+ char devname[255];
+ int device_fd;
+ int rc = 0;
+
+ ctx->lo_num = FindNextAvailableLoop();
+ if (ctx->lo_num < 0) {
+ LOG_ERROR("No loop devices available\n");
+ return -ENXIO;
+ }
+
+ sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
+ device_fd = open(devname, O_RDWR);
+ if (device_fd < 0) {
+ LOG_ERROR("failed to open loop device (%d)\n", errno);
+ return -errno;
+ }
+
+ if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
+ LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
+ rc = -errno;
+ }
+ close(device_fd);
+ return rc;
+}
+
+static int AsecDestroyLoop(struct asec_context *ctx)
+{
+ char devname[255];
+ int device_fd;
+ int rc = 0;
+
+ sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
+ device_fd = open(devname, O_RDONLY);
+ if (device_fd < 0) {
+ LOG_ERROR("Failed to open loop (%d)\n", errno);
+ return -errno;
+ }
+
+ if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
+ LOG_ERROR("Failed to destroy loop (%d)\n", errno);
+ rc = -errno;
+ }
+
+ close(device_fd);
+ return rc;
+}
+
+int AsecStart(void *Handle)
+{
+ struct asec_context *ctx = (struct asec_context *) Handle;
+ char value[PROPERTY_VALUE_MAX];
+ int rc = 0;
+
+ if (!ctx)
+ return -EINVAL;
+
+ if (ctx->started)
+ return -EBUSY;
+
+ LOG_ASEC("AsecStart(%s):\n", ctx->name);
+
+ NotifyAsecState(ASEC_BUSY, ctx->dstPath);
+
+ if ((rc = AsecLoadModules()) < 0) {
+ LOG_ERROR("AsecStart: Failed to load kernel modules\n");
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+
+ if ((rc = AsecLoadGenerateKey(ctx))) {
+ LOG_ERROR("AsecStart: Failed to load / generate key\n");
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+
+ if ((rc = AsecOpenCreateCache(ctx)) < 0) {
+ LOG_ERROR("AsecStart: Failed to open / create cache\n");
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+
+ if ((rc = AsecCreateLoop(ctx)) < 0) {
+ LOG_ERROR("AsecStart: Failed to create loop\n");
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ goto fail_closecache;
+ }
+
+ if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
+ LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ goto fail_destroyloop;
+ }
+
+ if (ctx->needs_format) {
+ if ((rc = AsecFormatFilesystem(ctx))) {
+ LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ goto fail_destroydm;
+ }
+ ctx->needs_format = 0;
+ } else {
+ if ((rc = AsecCheckFilesystem(ctx))) {
+ LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ goto fail_destroydm;
+ }
+ }
+
+ if ((rc = AsecMountCache(ctx)) < 0) {
+ LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ goto fail_destroydm;
+ }
+
+ NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
+ ctx->started = true;
+
+ return rc;
+
+ fail_destroydm:
+ AsecDestroyDeviceMapping(ctx);
+ fail_destroyloop:
+ AsecDestroyLoop(ctx);
+ fail_closecache:
+ AsecCloseCache(ctx);
+ return rc;
+}
+
+int AsecStop(void *Handle)
+{
+ struct asec_context *ctx = (struct asec_context *) Handle;
+ int rc = 0;
+
+ if (!ctx->started)
+ return -EINVAL;
+
+ LOG_ASEC("AsecStop(%s):\n", ctx->name);
+
+ NotifyAsecState(ASEC_BUSY, ctx->dstPath);
+
+ if ((rc = AsecUnmountCache(ctx)) < 0) {
+ LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+
+ if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
+ LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+
+ if ((rc = AsecDestroyLoop(ctx)) < 0) {
+ LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+
+ AsecCloseCache(ctx);
+
+ if ((rc = AsecUnloadModules()) < 0) {
+ if (rc == -EAGAIN) {
+ LOG_ASEC("AsecStop: Kernel modules still in use\n");
+ } else {
+ LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
+ NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+ return rc;
+ }
+ }
+
+ ctx->started = false;
+ NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
+ return rc;
+}
diff --git a/mountd/ASEC.h b/mountd/ASEC.h
new file mode 100644
index 000000000..c87b28877
--- /dev/null
+++ b/mountd/ASEC.h
@@ -0,0 +1,66 @@
+#ifndef _ASEC_H
+#define _ASEC_H
+
+#define ASEC_STORES_MAX 4
+#define MAX_LOOP 8
+
+typedef enum AsecState {
+ // Feature disabled
+ ASEC_DISABLED,
+
+ // Feature enabled and operational
+ ASEC_AVAILABLE,
+
+ // Busy
+ ASEC_BUSY,
+
+ // Internal Error
+ ASEC_FAILED_INTERR,
+
+ // No media available
+ ASEC_FAILED_NOMEDIA,
+
+ // Media is corrupt
+ ASEC_FAILED_BADMEDIA,
+
+ // Key mismatch
+ ASEC_FAILED_BADKEY,
+} AsecState;
+
+/*
+ * ASEC commands
+ */
+#define ASEC_CMD_SEND_STATUS "asec_send_status"
+#define ASEC_CMD_ENABLE "asec_enable"
+#define ASEC_CMD_DISABLE "asec_disable"
+
+/*
+ * ASEC events
+ */
+
+// These events correspond to the states in the AsecState enum.
+// A path to the ASEC mount point follows the colon
+#define ASEC_EVENT_DISABLED "asec_disabled:"
+#define ASEC_EVENT_AVAILABLE "asec_available:"
+#define ASEC_EVENT_BUSY "asec_busy:"
+#define ASEC_EVENT_FAILED_INTERR "asec_failed_interror:"
+#define ASEC_EVENT_FAILED_NOMEDIA "asec_failed_nomedia"
+#define ASEC_EVENT_FAILED_BADMEDIA "asec_failed_badmedia:"
+#define ASEC_EVENT_FAILED_BADKEY "asec_failed_badkey:"
+
+/*
+ * System Properties
+ */
+
+#define ASEC_ENABLED "asec.enabled"
+
+#define ASEC_STATUS "ro.asec.status"
+#define ASEC_STATUS_DISABLED "disabled"
+#define ASEC_STATUS_AVAILABLE "available"
+#define ASEC_STATUS_BUSY "busy"
+#define ASEC_STATUS_FAILED_INTERR "internal_error"
+#define ASEC_STATUS_FAILED_NOMEDIA "no_media"
+#define ASEC_STATUS_FAILED_BADMEDIA "bad_media"
+#define ASEC_STATUS_FAILED_BADKEY "bad_key"
+
+#endif
diff --git a/mountd/Android.mk b/mountd/Android.mk
index 87bcef3ec..bc128ac0e 100644
--- a/mountd/Android.mk
+++ b/mountd/Android.mk
@@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
AutoMount.c \
ProcessKiller.c \
Server.c \
- mountd.c
+ mountd.c \
+ ASEC.c
LOCAL_MODULE:= mountd
diff --git a/mountd/AutoMount.c b/mountd/AutoMount.c
index bfe8ad105..0aac871d5 100644
--- a/mountd/AutoMount.c
+++ b/mountd/AutoMount.c
@@ -76,17 +76,20 @@ typedef struct MountPoint {
// mount point for device
const char* mountPoint;
+
+ // path to the UMS driver file for specifying the block device path
+ const char* driverStorePath;
// true if device can be shared via
// USB mass storage
boolean enableUms;
-
+
+ // Array of ASEC handles
+ void *asecHandles[ASEC_STORES_MAX];
+
// true if the device is being shared via USB mass storage
boolean umsActive;
- // logical unit number (for UMS)
- int lun;
-
// current state of the mount point
MountState state;
@@ -100,11 +103,13 @@ typedef struct MountPoint {
// list of our mount points (does not change after initialization)
static MountPoint* sMountPointList = NULL;
-static int sNextLun = 0;
boolean gMassStorageEnabled = false;
boolean gMassStorageConnected = false;
static pthread_t sAutoMountThread = 0;
+static pid_t gExcludedPids[2] = {-1, -1};
+
+static const char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
// number of mount points that have timeouts pending
static int sRetriesPending = 0;
@@ -116,15 +121,18 @@ static pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
// via USB mass storage.
static void SetBackingStore(MountPoint* mp, boolean enable)
{
- char path[PATH_MAX];
int fd;
+ if (!mp->driverStorePath) {
+ LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
+ return;
+ }
+
LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
- snprintf(path, sizeof(path), "/sys/devices/platform/usb_mass_storage/lun%d/file", mp->lun);
- fd = open(path, O_WRONLY);
+ fd = open(mp->driverStorePath, O_WRONLY);
if (fd < 0)
{
- LOG_ERROR("could not open %s\n", path);
+ LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
}
else
{
@@ -192,6 +200,56 @@ static boolean IsLoopMounted(const char* path)
return result;
}
+static int CheckFilesystem(const char *device)
+{
+ char cmdline[255];
+ int rc;
+
+ // XXX: SAN: Check for FAT signature
+
+ int result = access(FSCK_MSDOS_PATH, X_OK);
+ if (result != 0) {
+ LOG_MOUNT("CheckFilesystem(%s): fsck_msdos not found (skipping checks)\n", device);
+ return 0;
+ }
+
+ sprintf(cmdline, "%s -p %s", FSCK_MSDOS_PATH, device);
+ LOG_MOUNT("Checking filesystem (%s)\n", cmdline);
+
+ // XXX: Notify framework we're disk checking
+
+ // XXX: PROTECT FROM VIKING KILLER
+ if ((rc = system(cmdline)) < 0) {
+ LOG_ERROR("Error executing disk check command (%d)\n", errno);
+ return -errno;
+ }
+
+ rc = WEXITSTATUS(rc);
+
+ if (rc == 0) {
+ LOG_MOUNT("Filesystem check completed OK\n");
+ return 0;
+ } else if (rc == 1) {
+ LOG_MOUNT("Filesystem check failed (invalid usage)\n");
+ return -EINVAL;
+ } else if (rc == 2) {
+ LOG_MOUNT("Filesystem check failed (unresolved issues)\n");
+ return -EIO;
+ } else if (rc == 4) {
+ LOG_MOUNT("Filesystem check failed (root changed)\n");
+ return -EIO;
+ } else if (rc == 8) {
+ LOG_MOUNT("Filesystem check failed (general failure)\n");
+ return -EIO;
+ } else if (rc == 12) {
+ LOG_MOUNT("Filesystem check failed (exit signaled)\n");
+ return -EIO;
+ } else {
+ LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
+ return -EIO;
+ }
+}
+
static int DoMountDevice(const char* device, const char* mountPoint)
{
LOG_MOUNT("mounting %s at %s\n", device, mountPoint);
@@ -237,6 +295,17 @@ static int DoMountDevice(const char* device, const char* mountPoint)
if (result != 0)
return result;
+ if ((result = CheckFilesystem(device))) {
+ LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
+ // XXX: Notify framework - need a new SDCARD state for the following:
+ // - SD cards which are not present
+ // - SD cards with no partition table
+ // - SD cards with no filesystem
+ // - SD cards with bad filesystem
+ return result;
+ }
+
+
// Extra safety measures:
flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
// Also, set fmask = 711 so that files cannot be marked executable,
@@ -254,6 +323,24 @@ static int DoMountDevice(const char* device, const char* mountPoint)
if (result == 0) {
NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
+
+ MountPoint* mp = sMountPointList;
+ while (mp) {
+ if (!strcmp(mountPoint, mp->mountPoint)) {
+ int i;
+
+ for (i = 0; i < ASEC_STORES_MAX; i++) {
+ if (mp->asecHandles[i] != NULL) {
+ int a_result;
+ if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
+ LOG_ERROR("ASEC start failure (%d)\n", a_result);
+ }
+ }
+ }
+ break;
+ }
+ mp = mp -> next;
+ }
} else if (errno == EBUSY) {
// ignore EBUSY, since it usually means the device is already mounted
result = 0;
@@ -267,32 +354,39 @@ static int DoMountDevice(const char* device, const char* mountPoint)
return result;
}
-static int DoUnmountDevice(const char* mountPoint)
+static int DoUnmountDevice(MountPoint *mp)
{
- boolean loop = IsLoopMounted(mountPoint);
- int result = umount(mountPoint);
+ boolean loop = IsLoopMounted(mp->mountPoint);
+ int i;
+
+ for (i = 0; i < ASEC_STORES_MAX; i++) {
+ if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
+ AsecStop(mp->asecHandles[i]);
+ }
+
+ int result = umount(mp->mountPoint);
LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
if (result == 0)
{
- if (loop)
- {
- // free the loop device
- int loop_fd = open(LOOP_DEVICE, O_RDONLY);
- if (loop_fd < -1) {
- LOG_ERROR("open loop device failed\n");
- }
- if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
- LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
- }
-
- close(loop_fd);
- }
-
#if CREATE_MOUNT_POINTS
rmdir(mountPoint);
#endif
- NotifyMediaState(mountPoint, MEDIA_UNMOUNTED, false);
+ NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
+ }
+
+ if (loop)
+ {
+ // free the loop device
+ int loop_fd = open(LOOP_DEVICE, O_RDONLY);
+ if (loop_fd < -1) {
+ LOG_ERROR("open loop device failed\n");
+ }
+ if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
+ LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
+ }
+
+ close(loop_fd);
}
// ignore EINVAL and ENOENT, since it usually means the device is already unmounted
@@ -408,7 +502,7 @@ static void RequestUnmount(MountPoint* mp, MountState retryState)
sync();
DropSystemCaches();
- if (DoUnmountDevice(mp->mountPoint) == 0)
+ if (DoUnmountDevice(mp) == 0)
{
SetState(mp, kUnmounted);
if (retryState == kUnmountingForUms)
@@ -502,6 +596,8 @@ static void HandleMediaInserted(const char* device)
{
MountPoint* mp = sMountPointList;
+ LOG_MOUNT("HandleMediaInserted(%s):\n", device);
+
while (mp)
{
// see if the device matches mount point's block device
@@ -573,7 +669,7 @@ static void HandleRetries()
}
else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
{
- if (DoUnmountDevice(mp->mountPoint) == 0)
+ if (DoUnmountDevice(mp) == 0)
{
// unmounting succeeded
// start mass storage, if state is kUnmountingForUms
@@ -594,8 +690,25 @@ static void HandleRetries()
// send SIGKILL instead of SIGTERM if the first attempt did not succeed
boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
+ int i;
+
+ for (i = 0; i < ASEC_STORES_MAX; i++) {
+ if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
+ LOG_MOUNT("Killing processes for ASEC path '%s'\n",
+ AsecMountPoint(mp->asecHandles[i]));
+ KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
+ sigkill,
+ gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
+
+ // Now that we've killed the processes, try to stop the volume again
+ AsecStop(mp->asecHandles[i]);
+ }
+ }
+
// unmounting the device is failing, so start killing processes
- KillProcessesWithOpenFiles(mp->mountPoint, sigkill);
+ KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids,
+ sizeof(gExcludedPids) / sizeof(pid_t));
+
}
}
}
@@ -676,6 +789,8 @@ static void* AutoMountThread(void* arg)
int id;
struct sigaction actions;
+ gExcludedPids[1] = getpid();
+
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
@@ -829,7 +944,9 @@ void EnableMassStorage(boolean enable)
void MountMedia(const char* mountPoint)
{
MountPoint* mp = sMountPointList;
-
+
+ LOG_MOUNT("MountMedia(%s)\n", mountPoint);
+
pthread_mutex_lock(&sMutex);
while (mp)
{
@@ -883,27 +1000,48 @@ boolean IsMassStorageConnected()
*
***********************************************/
-void AddMountPoint(const char* device, const char* mountPoint, boolean enableUms)
+void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
{
MountPoint* newMountPoint;
- LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s\n", device, mountPoint);
+ LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
// add a new MountPoint to the head of our linked list
newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
newMountPoint->device = device;
newMountPoint->mountPoint = mountPoint;
+ newMountPoint->driverStorePath = driverStorePath;
newMountPoint->enableUms = enableUms;
newMountPoint->umsActive = false;
- if (enableUms)
- newMountPoint->lun = sNextLun++;
newMountPoint->state = kUnmounted;
newMountPoint->retryCount = 0;
// add to linked list
newMountPoint->next = sMountPointList;
sMountPointList = newMountPoint;
+ return newMountPoint;
}
+int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
+ const char *mount_point, const char *crypt)
+{
+ MountPoint *mp = (MountPoint *) Mp;
+ int i;
+
+ for (i = 0; i < ASEC_STORES_MAX; i++) {
+ if (!mp->asecHandles[i])
+ break;
+ }
+
+ if (i == ASEC_STORES_MAX) {
+ LOG_ERROR("Maximum # of ASEC stores exceeded\n");
+ return -EINVAL;
+ }
+
+ if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
+ return -1;
+
+ return 0;
+}
static void MountDevices()
{
MountPoint* mp = sMountPointList;
@@ -916,6 +1054,8 @@ static void MountDevices()
void StartAutoMounter()
{
+ gExcludedPids[0] = getpid();
+
gMassStorageConnected = ReadMassStorageState();
LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
diff --git a/mountd/ProcessKiller.c b/mountd/ProcessKiller.c
index 3ce7aa81c..e37777446 100644
--- a/mountd/ProcessKiller.c
+++ b/mountd/ProcessKiller.c
@@ -177,7 +177,7 @@ static int get_pid(const char* s)
}
// hunt down and kill processes that have files open on the given mount point
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill)
+void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
{
DIR* dir;
struct dirent* de;
@@ -200,8 +200,21 @@ void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill)
|| CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
)
{
- LOG_ERROR("Killing process %d\n", pid);
- kill(pid, (sigkill ? SIGKILL : SIGTERM));
+ int i;
+ boolean hit = false;
+
+ for (i = 0; i < num_excluded; i++) {
+ if (pid == excluded[i]) {
+ LOG_ERROR("I just need a little more TIME captain!\n");
+ hit = true;
+ break;
+ }
+ }
+
+ if (!hit) {
+ LOG_ERROR("Killing process %d\n", pid);
+ kill(pid, (sigkill ? SIGKILL : SIGTERM));
+ }
}
}
diff --git a/mountd/Server.c b/mountd/Server.c
index 14b383001..64459bd88 100644
--- a/mountd/Server.c
+++ b/mountd/Server.c
@@ -19,6 +19,7 @@
*/
#include "mountd.h"
+#include "ASEC.h"
#include <cutils/properties.h>
#include <cutils/sockets.h>
@@ -43,6 +44,10 @@ static pthread_mutex_t sWriteMutex = PTHREAD_MUTEX_INITIALIZER;
// path for media that failed to mount before the runtime is connected
static char* sDeferredUnmountableMediaPath = NULL;
+// last asec msg before the runtime was connected
+static char* sAsecDeferredMessage = NULL;
+static char* sAsecDeferredArgument = NULL;
+
static int Write(const char* message)
{
int result = -1;
@@ -107,6 +112,18 @@ static void DoCommand(const char* command)
{
const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
UnmountMedia(path);
+ }
+ else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
+ LOG_ASEC("Got ASEC_CMD_ENABLE\n");
+ // XXX: SAN: Impliment
+ }
+ else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
+ LOG_ASEC("Got ASEC_CMD_DISABLE\n");
+ // XXX: SAN: Impliment
+ }
+ else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
+ LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
+ // XXX: SAN: Impliment
}
else
LOGE("unknown command %s\n", command);
@@ -145,6 +162,15 @@ int RunServer()
sDeferredUnmountableMediaPath = NULL;
}
+ if (sAsecDeferredMessage) {
+
+ if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
+ LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
+ free(sAsecDeferredMessage);
+ free(sAsecDeferredArgument);
+ sAsecDeferredMessage = sAsecDeferredArgument = NULL;
+ }
+
while (1)
{
char buffer[101];
@@ -187,6 +213,61 @@ void SendUnmountRequest(const char* path)
Write2(MOUNTD_REQUEST_EJECT, path);
}
+void NotifyAsecState(AsecState state, const char *argument)
+{
+ const char *event = NULL;
+ const char *status = NULL;
+ boolean deferr = true;;
+
+ switch (state) {
+ case ASEC_DISABLED:
+ event = ASEC_EVENT_DISABLED;
+ status = ASEC_STATUS_DISABLED;
+ break;
+ case ASEC_AVAILABLE:
+ event = ASEC_EVENT_AVAILABLE;
+ status = ASEC_STATUS_AVAILABLE;
+ break;
+ case ASEC_BUSY:
+ event = ASEC_EVENT_BUSY;
+ status = ASEC_STATUS_BUSY;
+ deferr = false;
+ break;
+ case ASEC_FAILED_INTERR:
+ event = ASEC_EVENT_FAILED_INTERR;
+ status = ASEC_STATUS_FAILED_INTERR;
+ break;
+ case ASEC_FAILED_NOMEDIA:
+ event = ASEC_EVENT_FAILED_NOMEDIA;
+ status = ASEC_STATUS_FAILED_NOMEDIA;
+ break;
+ case ASEC_FAILED_BADMEDIA:
+ event = ASEC_EVENT_FAILED_BADMEDIA;
+ status = ASEC_STATUS_FAILED_BADMEDIA;
+ break;
+ case ASEC_FAILED_BADKEY:
+ event = ASEC_EVENT_FAILED_BADKEY;
+ status = ASEC_STATUS_FAILED_BADKEY;
+ break;
+ default:
+ LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
+ return;
+ }
+
+ property_set(ASEC_STATUS, status);
+
+ int result = Write2(event, argument);
+ if ((result < 0) && deferr) {
+ if (sAsecDeferredMessage)
+ free(sAsecDeferredMessage);
+ sAsecDeferredMessage = strdup(event);
+ if (sAsecDeferredArgument)
+ free(sAsecDeferredArgument);
+ sAsecDeferredArgument = strdup(argument);
+ LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
+ }
+}
+
void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
{
const char* event = NULL;
diff --git a/mountd/dm-ioctl.h b/mountd/dm-ioctl.h
new file mode 100644
index 000000000..ee5c3508b
--- /dev/null
+++ b/mountd/dm-ioctl.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DM_IOCTL_V4_H
+#define _LINUX_DM_IOCTL_V4_H
+
+#ifdef linux
+# include <linux/types.h>
+#endif
+
+#define DM_DIR "mapper" /* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
+
+/*
+ * A traditional ioctl interface for the device mapper.
+ *
+ * Each device can have two tables associated with it, an
+ * 'active' table which is the one currently used by io passing
+ * through the device, and an 'inactive' one which is a table
+ * that is being prepared as a replacement for the 'active' one.
+ *
+ * DM_VERSION:
+ * Just get the version information for the ioctl interface.
+ *
+ * DM_REMOVE_ALL:
+ * Remove all dm devices, destroy all tables. Only really used
+ * for debug.
+ *
+ * DM_LIST_DEVICES:
+ * Get a list of all the dm device names.
+ *
+ * DM_DEV_CREATE:
+ * Create a new device, neither the 'active' or 'inactive' table
+ * slots will be filled. The device will be in suspended state
+ * after creation, however any io to the device will get errored
+ * since it will be out-of-bounds.
+ *
+ * DM_DEV_REMOVE:
+ * Remove a device, destroy any tables.
+ *
+ * DM_DEV_RENAME:
+ * Rename a device.
+ *
+ * DM_SUSPEND:
+ * This performs both suspend and resume, depending which flag is
+ * passed in.
+ * Suspend: This command will not return until all pending io to
+ * the device has completed. Further io will be deferred until
+ * the device is resumed.
+ * Resume: It is no longer an error to issue this command on an
+ * unsuspended device. If a table is present in the 'inactive'
+ * slot, it will be moved to the active slot, then the old table
+ * from the active slot will be _destroyed_. Finally the device
+ * is resumed.
+ *
+ * DM_DEV_STATUS:
+ * Retrieves the status for the table in the 'active' slot.
+ *
+ * DM_DEV_WAIT:
+ * Wait for a significant event to occur to the device. This
+ * could either be caused by an event triggered by one of the
+ * targets of the table in the 'active' slot, or a table change.
+ *
+ * DM_TABLE_LOAD:
+ * Load a table into the 'inactive' slot for the device. The
+ * device does _not_ need to be suspended prior to this command.
+ *
+ * DM_TABLE_CLEAR:
+ * Destroy any table in the 'inactive' slot (ie. abort).
+ *
+ * DM_TABLE_DEPS:
+ * Return a set of device dependencies for the 'active' table.
+ *
+ * DM_TABLE_STATUS:
+ * Return the targets status for the 'active' table.
+ *
+ * DM_TARGET_MSG:
+ * Pass a message string to the target at a specific offset of a device.
+ *
+ * DM_DEV_SET_GEOMETRY:
+ * Set the geometry of a device by passing in a string in this format:
+ *
+ * "cylinders heads sectors_per_track start_sector"
+ *
+ * Beware that CHS geometry is nearly obsolete and only provided
+ * for compatibility with dm devices that can be booted by a PC
+ * BIOS. See struct hd_geometry for range limits. Also note that
+ * the geometry is erased if the device size changes.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start. If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+ /*
+ * The version number is made up of three parts:
+ * major - no backward or forward compatibility,
+ * minor - only backwards compatible,
+ * patch - both backwards and forwards compatible.
+ *
+ * All clients of the ioctl interface should fill in the
+ * version number of the interface that they were
+ * compiled with.
+ *
+ * All recognised ioctl commands (ie. those that don't
+ * return -ENOTTY) fill out this field, even if the
+ * command failed.
+ */
+ uint32_t version[3]; /* in/out */
+ uint32_t data_size; /* total size of data passed in
+ * including this struct */
+
+ uint32_t data_start; /* offset to start of data
+ * relative to start of this struct */
+
+ uint32_t target_count; /* in/out */
+ int32_t open_count; /* out */
+ uint32_t flags; /* in/out */
+ uint32_t event_nr; /* in/out */
+ uint32_t padding;
+
+ uint64_t dev; /* in/out */
+
+ char name[DM_NAME_LEN]; /* device name */
+ char uuid[DM_UUID_LEN]; /* unique identifier for
+ * the block device */
+ char data[7]; /* padding or data */
+};
+
+/*
+ * Used to specify tables. These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+ uint64_t sector_start;
+ uint64_t length;
+ int32_t status; /* used when reading from kernel only */
+
+ /*
+ * Location of the next dm_target_spec.
+ * - When specifying targets on a DM_TABLE_LOAD command, this value is
+ * the number of bytes from the start of the "current" dm_target_spec
+ * to the start of the "next" dm_target_spec.
+ * - When retrieving targets on a DM_TABLE_STATUS command, this value
+ * is the number of bytes from the start of the first dm_target_spec
+ * (that follows the dm_ioctl struct) to the start of the "next"
+ * dm_target_spec.
+ */
+ uint32_t next;
+
+ char target_type[DM_MAX_TYPE_NAME];
+
+ /*
+ * Parameter string starts immediately after this object.
+ * Be careful to add padding after string to ensure correct
+ * alignment of subsequent dm_target_spec.
+ */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+ uint32_t count; /* Array size */
+ uint32_t padding; /* unused */
+ uint64_t dev[0]; /* out */
+};
+
+/*
+ * Used to get a list of all dm devices.
+ */
+struct dm_name_list {
+ uint64_t dev;
+ uint32_t next; /* offset to the next record from
+ the _start_ of this */
+ char name[0];
+};
+
+/*
+ * Used to retrieve the target versions
+ */
+struct dm_target_versions {
+ uint32_t next;
+ uint32_t version[3];
+
+ char name[0];
+};
+
+/*
+ * Used to pass message to a target
+ */
+struct dm_target_msg {
+ uint64_t sector; /* Device sector */
+
+ char message[0];
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+ /* Top level cmds */
+ DM_VERSION_CMD = 0,
+ DM_REMOVE_ALL_CMD,
+ DM_LIST_DEVICES_CMD,
+
+ /* device level cmds */
+ DM_DEV_CREATE_CMD,
+ DM_DEV_REMOVE_CMD,
+ DM_DEV_RENAME_CMD,
+ DM_DEV_SUSPEND_CMD,
+ DM_DEV_STATUS_CMD,
+ DM_DEV_WAIT_CMD,
+
+ /* Table level cmds */
+ DM_TABLE_LOAD_CMD,
+ DM_TABLE_CLEAR_CMD,
+ DM_TABLE_DEPS_CMD,
+ DM_TABLE_STATUS_CMD,
+
+ /* Added later */
+ DM_LIST_VERSIONS_CMD,
+ DM_TARGET_MSG_CMD,
+ DM_DEV_SET_GEOMETRY_CMD
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
+
+#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
+#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
+#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
+#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
+
+#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
+
+#define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
+#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR 4
+#define DM_VERSION_MINOR 13
+#define DM_VERSION_PATCHLEVEL 0
+#define DM_VERSION_EXTRA "-ioctl (2007-10-18)"
+
+/* Status bits */
+#define DM_READONLY_FLAG (1 << 0) /* In/Out */
+#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */
+#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */
+
+/*
+ * Flags that indicate whether a table is present in either of
+ * the two table slots that a device has.
+ */
+#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */
+#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
+
+/*
+ * Indicates that the buffer passed in wasn't big enough for the
+ * results.
+ */
+#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */
+
+/*
+ * This flag is now ignored.
+ */
+#define DM_SKIP_BDGET_FLAG (1 << 9) /* In */
+
+/*
+ * Set this to avoid attempting to freeze any filesystem when suspending.
+ */
+#define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */
+
+/*
+ * Set this to suspend without flushing queued ios.
+ */
+#define DM_NOFLUSH_FLAG (1 << 11) /* In */
+
+#endif /* _LINUX_DM_IOCTL_H */
diff --git a/mountd/mountd.c b/mountd/mountd.c
index fb54fe68d..27ec8de90 100644
--- a/mountd/mountd.c
+++ b/mountd/mountd.c
@@ -39,6 +39,54 @@
FILE* logFile;
#endif
+struct asec_cfg {
+ const char *name;
+ const char *backing_file;
+ const char *size;
+ const char *mount_point;
+ const char *crypt;
+};
+
+static int ProcessAsecData(cnode *node, struct asec_cfg *stores, int idx)
+{
+ cnode *child = node->first_child;
+ const char *name = NULL;
+ const char *file = NULL;
+ const char *size = NULL;
+ const char *mp = NULL;
+ const char *crypt = NULL;
+
+ LOG_ASEC("ProcessAsecData(%s, %p, %d)\n", node->name, stores, idx);
+
+ while (child) {
+ if (!strcmp(child->name, "name"))
+ name = child->value;
+ else if (!strcmp(child->name, "backing_file"))
+ file = child->value;
+ else if (!strcmp(child->name, "size"))
+ size = child->value;
+ else if (!strcmp(child->name, "mount_point"))
+ mp = child->value;
+ else if (!strcmp(child->name, "crypt"))
+ crypt = child->value;
+ child = child->next;
+ }
+
+ if (!name || !file || !size || !mp || !crypt) {
+ LOG_ERROR("Missing required token from config. Skipping ASEC volume\n");
+ return -1;
+ } else if (idx == ASEC_STORES_MAX) {
+ LOG_ERROR("Maximum # of ASEC stores already defined\n");
+ return -1;
+ }
+
+ stores[idx].name = name;
+ stores[idx].backing_file = file;
+ stores[idx].size = size;
+ stores[idx].mount_point = mp;
+ stores[idx].crypt = crypt;
+ return ++idx;
+}
static void ReadConfigFile(const char* path)
{
@@ -54,18 +102,31 @@ static void ReadConfigFile(const char* path)
{
const char* block_device = NULL;
const char* mount_point = NULL;
+ const char* driver_store_path = NULL;
boolean enable_ums = false;
cnode* child = node->first_child;
-
+ struct asec_cfg asec_stores[ASEC_STORES_MAX];
+ int asec_idx = 0;
+
+ memset(asec_stores, 0, sizeof(asec_stores));
+
while (child)
{
const char* name = child->name;
const char* value = child->value;
-
- if (strcmp(name, "block_device") == 0)
+
+ if (!strncmp(name, "asec_", 5)) {
+ int rc = ProcessAsecData(child, asec_stores, asec_idx);
+ if (rc < 0) {
+ LOG_ERROR("Error processing ASEC cfg data\n");
+ } else
+ asec_idx = rc;
+ } else if (strcmp(name, "block_device") == 0)
block_device = value;
else if (strcmp(name, "mount_point") == 0)
mount_point = value;
+ else if (strcmp(name, "driver_store_path") == 0)
+ driver_store_path = value;
else if (strcmp(name, "enable_ums") == 0 &&
strcmp(value, "true") == 0)
enable_ums = true;
@@ -76,7 +137,14 @@ static void ReadConfigFile(const char* path)
// mount point and removable fields are optional
if (block_device && mount_point)
{
- AddMountPoint(block_device, mount_point, enable_ums);
+ void *mp = AddMountPoint(block_device, mount_point, driver_store_path, enable_ums);
+ int i;
+
+ for (i = 0; i < asec_idx; i++) {
+ AddAsecToMountPoint(mp, asec_stores[i].name, asec_stores[i].backing_file,
+ asec_stores[i].size, asec_stores[i].mount_point,
+ asec_stores[i].crypt);
+ }
}
}
diff --git a/mountd/mountd.h b/mountd/mountd.h
index 746a41483..9b6248479 100644
--- a/mountd/mountd.h
+++ b/mountd/mountd.h
@@ -20,21 +20,28 @@
#define LOG_TAG "mountd"
#include "cutils/log.h"
+#include "ASEC.h"
+
typedef int boolean;
enum {
false = 0,
true = 1
};
+#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
+
// Set this for logging error messages
#define ENABLE_LOG_ERROR
// set this to log automounter events
-//#define ENABLE_LOG_MOUNT
+#define ENABLE_LOG_MOUNT
// set this to log server events
//#define ENABLE_LOG_SERVER
+// set this to log ASEC events
+#define ENABLE_LOG_ASEC
+
#ifdef ENABLE_LOG_ERROR
#define LOG_ERROR(fmt, args...) \
{ LOGE(fmt , ## args); }
@@ -59,6 +66,14 @@ enum {
do { } while (0)
#endif /* ENABLE_LOG_SERVER */
+#ifdef ENABLE_LOG_ASEC
+#define LOG_ASEC(fmt, args...) \
+ { LOGD(fmt , ## args); }
+#else
+#define LOG_ASEC(fmt, args...) \
+ do { } while (0)
+#endif /* ENABLE_LOG_ASEC */
+
typedef enum MediaState {
// no media in SD card slot
@@ -135,7 +150,11 @@ void UnmountMedia(const char* mountPoint);
void EnableMassStorage(boolean enable);
// call this before StartAutoMounter() to add a mount point to monitor
-void AddMountPoint(const char* device, const char* mountPoint, boolean enableUms);
+void *AddMountPoint(const char* device, const char* mountPoint, const char* driverStorePath,
+ boolean enableUms);
+
+int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file,
+ const char *size, const char *mount_point, const char *crypt);
// start automounter thread
void StartAutoMounter();
@@ -144,9 +163,19 @@ void StartAutoMounter();
void NotifyExistingMounts();
+// ASEC.c
+
+void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
+ const char *Size, const char *DstPath, const char *Crypt);
+int AsecStart(void *Handle);
+int AsecStop(void *Handle);
+void AsecDeinit(void *Handle);
+boolean AsecIsStarted(void *Handle);
+const char *AsecMountPoint(void *Handle);
+
// ProcessKiller.c
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill);
+void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
// Server.c
@@ -155,5 +184,5 @@ int RunServer();
void SendMassStorageConnected(boolean connected);
void SendUnmountRequest(const char* path);
void NotifyMediaState(const char* path, MediaState state, boolean readOnly);
-
+void NotifyAsecState(AsecState state, const char *argument);
#endif // MOUNTD_H__
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 756005b30..7ff1a74a1 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -7,8 +7,7 @@ copy_from := \
etc/mountd.conf \
etc/dbus.conf \
etc/init.goldfish.sh \
- etc/hosts \
- etc/hcid.conf
+ etc/hosts
dont_copy := \
etc/init.gprs-pppd \
@@ -28,10 +27,13 @@ ALL_PREBUILT += $(copy_to)
# files that live under /...
+# Only copy init.rc if the target doesn't have its own.
+ifneq ($(TARGET_PROVIDES_INIT_RC),true)
file := $(TARGET_ROOT_OUT)/init.rc
$(file) : $(LOCAL_PATH)/init.rc | $(ACP)
$(transform-prebuilt-to-target)
ALL_PREBUILT += $(file)
+endif
file := $(TARGET_ROOT_OUT)/init.goldfish.rc
$(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP)
diff --git a/rootdir/etc/dbus.conf b/rootdir/etc/dbus.conf
index 8742345eb..75586b92d 100644
--- a/rootdir/etc/dbus.conf
+++ b/rootdir/etc/dbus.conf
@@ -5,9 +5,6 @@
<!-- Our well-known bus type, do not change this -->
<type>system</type>
- <!-- Fork into daemon mode -->
- <fork/>
-
<!-- Only allow socket-credentials-based authentication -->
<auth>EXTERNAL</auth>
@@ -17,51 +14,14 @@
systems.) -->
<listen>unix:path=/dev/socket/dbus</listen>
+ <!-- Allow everything, D-Bus socket is protected by unix filesystem
+ permissions -->
<policy context="default">
- <!-- Deny everything then punch holes -->
- <deny send_interface="*"/>
- <deny receive_interface="*"/>
- <deny own="*"/>
- <!-- But allow all users to connect -->
+ <allow send_interface="*"/>
+ <allow receive_interface="*"/>
+ <allow own="*"/>
<allow user="*"/>
- <!-- Allow anyone to talk to the message bus -->
- <!-- FIXME I think currently these allow rules are always implicit
- even if they aren't in here -->
- <allow send_destination="org.freedesktop.DBus"/>
- <allow receive_sender="org.freedesktop.DBus"/>
- <!-- valid replies are always allowed -->
<allow send_requested_reply="true"/>
<allow receive_requested_reply="true"/>
</policy>
-
-
- <!-- Now punch holes for bluetooth -->
-
- <policy context="default">
- <allow own="*"/>
- <allow user="*"/>
- <allow send_destination="org.bluez.PasskeyAgent"/>
- <allow receive_sender="org.bluez.PasskeyAgent"/>
- <allow send_path="/org/bluez/PasskeyAgent"/>
- </policy>
-
- <policy user="root">
- <allow own="org.bluez"/>
- </policy>
-
- <policy at_console="true">
- <allow send_destination="org.bluez.Adapter"/>
- <allow receive_sender="org.bluez.Adapter"/>
-
- <allow send_path="/org/bluez/Adapter"/>
-
- <allow send_destination="org.bluez.Manager"/>
- <allow receive_sender="org.bluez.Manager"/>
-
- <allow send_path="/org/bluez/Manager"/>
-
- <allow send_destination="org.bluez.Security"/>
- <allow receive_sender="org.bluez.Security"/>
- </policy>
-
</busconfig>
diff --git a/rootdir/etc/hcid.conf b/rootdir/etc/hcid.conf
deleted file mode 100644
index 56df63a2d..000000000
--- a/rootdir/etc/hcid.conf
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# HCI daemon configuration file.
-#
-
-# HCId options
-options {
- # Automatically initialize new devices
- autoinit yes;
-
- # Security Manager mode
- # none - Security manager disabled
- # auto - Use local PIN for incoming connections
- # user - Always ask user for a PIN
- #
- security user;
-
- # Pairing mode
- # none - Pairing disabled
- # multi - Allow pairing with already paired devices
- # once - Pair once and deny successive attempts
- pairing multi;
-}
-
-# Default settings for HCI devices
-device {
- # Local device name
- # %d - device id
- # %h - host name
- # %b - ro.product.brand
- # %m - ro.product.model
- # %n - ro.product.name
- name "%m";
-
- # Local device class
- # 0x400000 - Service class: Telephony
- # 0x000200 - Major class: Phone
- # 0x00000C - Minor class: Smart phone
- class 0x40020C;
-
- # Default packet type
- #pkt_type DH1,DM1,HV1;
-
- # Inquiry and Page scan
- iscan disable;
- pscan enable;
-
- # Page timeout (in 0.625ms slots): 10 seconds
- pageto 16384;
-
- # Default link mode
- # none - no specific policy
- # accept - always accept incoming connections
- # master - become master on incoming connections,
- # deny role switch on outgoing connections
- lm accept;
-
- # Default link policy
- # none - no specific policy
- # rswitch - allow role switch
- # hold - allow hold mode
- # sniff - allow sniff mode
- # park - allow park mode
- lp rswitch,hold,sniff,park;
-}
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index 5975974b0..96480f3e8 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -16,11 +16,11 @@ on boot
stop dund
stop akmd
- setprop app.setupwizard.disable 1
+ setprop ro.setupwizard.mode EMULATOR
# enable Google-specific location features,
# like NetworkLocationProvider and LocationCollector
- setprop ro.com.google.enable_google_location_features 1
+ setprop ro.com.google.locationfeatures 1
# For the emulator, which bypasses Setup Wizard, you can specify
# account info for the device via these two properties. Google
@@ -39,8 +39,9 @@ service goldfish-setup /system/etc/init.goldfish.sh
oneshot
service qemud /system/bin/qemud
- socket qemud_gsm stream 666
- socket qemud_gps stream 666
+ socket qemud_gsm stream 666
+ socket qemud_gps stream 666
+ socket qemud_control stream 666
oneshot
# -Q is a special logcat option that forces the
diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf
index d9dfdede3..094a2c7af 100644
--- a/rootdir/etc/mountd.conf
+++ b/rootdir/etc/mountd.conf
@@ -10,4 +10,10 @@ mount {
## true if this mount point can be shared via USB mass storage
enable_ums true
+
+ ## path to the UMS driver file for specifying the block device path
+ ## use this for the mass_storage function driver
+ driver_store_path /sys/devices/platform/usb_mass_storage/lun0/file
+ ## use this for android_usb composite gadget driver
+ ##driver_store_path /sys/devices/platform/msm_hsusb/gadget/lun0/file
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 23daa0b00..3f8c6a01b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1,6 +1,8 @@
on init
+sysclktz 0
+
loglevel 3
# setup the global environment
@@ -118,6 +120,12 @@ on boot
chown radio system /sys/android_power/acquire_full_wake_lock
chown radio system /sys/android_power/acquire_partial_wake_lock
chown radio system /sys/android_power/release_wake_lock
+ chown radio system /sys/power/state
+ chown radio system /sys/power/wake_lock
+ chown radio system /sys/power/wake_unlock
+ chmod 0660 /sys/power/state
+ chmod 0660 /sys/power/wake_lock
+ chmod 0660 /sys/power/wake_unlock
chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/class/leds/keyboard-backlight/brightness
chown system system /sys/class/leds/lcd-backlight/brightness
@@ -193,6 +201,7 @@ service ril-daemon /system/bin/rild
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
+ onrestart write /sys/power/state on
service media /system/bin/mediaserver
user media
@@ -208,7 +217,8 @@ service dbus /system/bin/dbus-daemon --system --nofork
user bluetooth
group bluetooth net_bt_admin
-service hcid /system/bin/hcid -s -n -f /etc/hcid.conf
+#STOPSHIP: disable the verbose logging
+service hcid /system/bin/logwrapper /system/bin/hcid -d -s -n -f /etc/bluez/hcid.conf
socket bluetooth stream 660 bluetooth bluetooth
socket dbus_bluetooth stream 660 bluetooth bluetooth
# init.rc does not yet support applying capabilities, so run as root and
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index df8ba9fb6..b0c241e7d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -83,3 +83,8 @@ $(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
$(hide) ln -sf $(TOOLBOX_BINARY) $@
ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+
+# We need this so that the installed files could be picked up based on the
+# local module name
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
+ $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)