Merge commit 'remotes/korg/cupcake'
Conflicts: init/devices.c logwrapper/logwrapper.c mountd/AutoMount.c
This commit is contained in:
commit
77d0c65b95
79 changed files with 4188 additions and 575 deletions
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
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
|
||||
|
||||
endif
|
||||
|
|
139
adb/OVERVIEW.TXT
Normal file
139
adb/OVERVIEW.TXT
Normal file
|
@ -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.
|
245
adb/SERVICES.TXT
Normal file
245
adb/SERVICES.TXT
Normal file
|
@ -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
|
96
adb/adb.c
96
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;
|
||||
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 },
|
||||
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 }
|
||||
};
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
if (p == NULL)
|
||||
return;
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
/* use a comma/column/semi-colum/space separated list */
|
||||
while (*p) {
|
||||
int len, tagn;
|
||||
/* 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;
|
||||
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);
|
||||
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++;
|
||||
}
|
||||
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();
|
||||
|
|
23
adb/adb.h
23
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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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, ×tamp, &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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
162
adb/sockets.c
162
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){
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
¬ificationIterators[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");
|
||||
|
|
|
@ -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);
|
||||
|
|
106
adb/utils.c
Normal file
106
adb/utils.c
Normal file
|
@ -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;
|
||||
}
|
68
adb/utils.h
Normal file
68
adb/utils.h
Normal file
|
@ -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 */
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -47,6 +47,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:
|
||||
*
|
||||
|
|
296
include/arch/target_linux-x86/AndroidConfig.h
Normal file
296
include/arch/target_linux-x86/AndroidConfig.h
Normal file
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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/*" },
|
||||
|
|
|
@ -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];
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
36
init/bootchart.h
Normal file
36
init/bootchart.h
Normal file
|
@ -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 */
|
|
@ -65,7 +65,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;
|
||||
|
@ -75,7 +75,7 @@ static int insmod(const char *filename)
|
|||
if (!module)
|
||||
return -1;
|
||||
|
||||
ret = init_module(module, size, "");
|
||||
ret = init_module(module, size, options);
|
||||
|
||||
free(module);
|
||||
|
||||
|
@ -173,9 +173,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)
|
||||
|
@ -382,6 +408,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]);
|
||||
|
|
|
@ -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 },
|
||||
|
@ -362,32 +365,32 @@ 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->subsystem, "sound", 5)) {
|
||||
base = "/dev/snd/";
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
21
init/init.c
21
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];
|
||||
|
@ -836,11 +827,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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
834
libcutils/tzstrftime.c
Normal file
834
libcutils/tzstrftime.c
Normal file
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
1
libpixelflinger/tests/Android.mk
Normal file
1
libpixelflinger/tests/Android.mk
Normal file
|
@ -0,0 +1 @@
|
|||
include $(all-subdir-makefiles)
|
15
libpixelflinger/tests/codegen/Android.mk
Normal file
15
libpixelflinger/tests/codegen/Android.mk
Normal file
|
@ -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)
|
21
libpixelflinger/tests/codegen/codegen.cpp
Normal file
21
libpixelflinger/tests/codegen/codegen.cpp
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "private/android_filesystem_config.h"
|
||||
#include "cutils/log.h"
|
||||
|
@ -33,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[]) {
|
||||
|
@ -92,41 +119,62 @@ void child(int argc, char* argv[]) {
|
|||
|
||||
int main(int argc, char* argv[]) {
|
||||
pid_t pid;
|
||||
int seg_fault_on_exit = 0;
|
||||
|
||||
int pipe_fds[2];
|
||||
int *parent_read = &pipe_fds[0];
|
||||
int *child_write = &pipe_fds[1];
|
||||
int parent_ptty;
|
||||
int child_ptty;
|
||||
char *child_devname = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (pipe(pipe_fds) < 0) {
|
||||
fatal("Cannot create pipe\n");
|
||||
if (strncmp(argv[1], "-d", 2) == 0) {
|
||||
seg_fault_on_exit = 1;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
|
|
@ -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))
|
||||
|
|
770
mountd/ASEC.c
Normal file
770
mountd/ASEC.c
Normal file
|
@ -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;
|
||||
}
|
66
mountd/ASEC.h
Normal file
66
mountd/ASEC.h
Normal file
|
@ -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
|
|
@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
|
|||
AutoMount.c \
|
||||
ProcessKiller.c \
|
||||
Server.c \
|
||||
mountd.c
|
||||
mountd.c \
|
||||
ASEC.c
|
||||
|
||||
LOCAL_MODULE:= mountd
|
||||
|
||||
|
|
|
@ -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,27 @@ 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;
|
||||
} else {
|
||||
#if CREATE_MOUNT_POINTS
|
||||
rmdir(mountPoint);
|
||||
|
@ -264,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
|
||||
|
@ -405,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)
|
||||
|
@ -499,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
|
||||
|
@ -570,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
|
||||
|
@ -591,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));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -673,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;
|
||||
|
@ -826,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)
|
||||
{
|
||||
|
@ -880,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;
|
||||
|
@ -913,6 +1054,8 @@ static void MountDevices()
|
|||
|
||||
void StartAutoMounter()
|
||||
{
|
||||
gExcludedPids[0] = getpid();
|
||||
|
||||
gMassStorageConnected = ReadMassStorageState();
|
||||
LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
304
mountd/dm-ioctl.h
Normal file
304
mountd/dm-ioctl.h
Normal file
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue