Merge commit 'remotes/korg/cupcake'

Conflicts:
	init/devices.c
	logwrapper/logwrapper.c
	mountd/AutoMount.c
This commit is contained in:
Jean-Baptiste Queru 2008-12-19 08:15:15 -08:00
commit 77d0c65b95
79 changed files with 4188 additions and 575 deletions

View file

@ -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 \

View file

@ -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
View 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
View 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

View file

@ -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();

View file

@ -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

View file

@ -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.

View file

@ -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);
}

View file

@ -55,7 +55,7 @@ static void END()
if(total_bytes == 0) return;
if (t == 0) /* prevent division by 0 :-) */
t = 1000000;
t = 1000000;
fprintf(stderr,"%lld KB/s (%d bytes in %lld.%03llds)\n",
((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
@ -227,14 +227,14 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
if(ret < 0) {
if(errno == EINTR)
continue;
continue;
fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
break;
}
sbuf->size = htoll(ret);
if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
err = -1;
err = -1;
break;
}
total_bytes += ret;
@ -259,7 +259,7 @@ static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *s
memcpy(sbuf->data, &file_buffer[total], count);
sbuf->size = htoll(count);
if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
err = -1;
err = -1;
break;
}
total += count;
@ -277,7 +277,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
if(len < 0) {
fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
return -1;
return -1;
}
sbuf->data[len] = '\0';
@ -377,10 +377,10 @@ static int sync_send(int fd, const char *lpath, const char *rpath,
}
if (file_buffer) {
write_data_buffer(fd, file_buffer, size, sbuf);
free(file_buffer);
write_data_buffer(fd, file_buffer, size, sbuf);
free(file_buffer);
} else if (S_ISREG(mode))
write_data_file(fd, lpath, sbuf);
write_data_file(fd, lpath, sbuf);
#ifdef HAVE_SYMLINKS
else if (S_ISLNK(mode))
write_data_link(fd, lpath, sbuf);
@ -641,7 +641,7 @@ static int local_build_list(copyinfo **filelist,
} else {
ci = mkcopyinfo(lpath, rpath, name, 0);
if(lstat(ci->src, &st)) {
closedir(d);
closedir(d);
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
return -1;
}
@ -651,7 +651,7 @@ static int local_build_list(copyinfo **filelist,
} else {
ci->time = st.st_mtime;
ci->mode = st.st_mode;
ci->size = st.st_size;
ci->size = st.st_size;
ci->next = *filelist;
*filelist = ci;
}
@ -707,12 +707,12 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i
unsigned int timestamp, mode, size;
if(sync_finish_readtime(fd, &timestamp, &mode, &size))
return 1;
if(size == ci->size) {
if(size == ci->size) {
/* for links, we cannot update the atime/mtime */
if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
(S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
(S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
ci->flag = 1;
}
}
}
}
for(ci = filelist; ci != 0; ci = next) {

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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 );
}

View file

@ -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){

View file

@ -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;

View file

@ -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);

View file

@ -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)) {

View file

@ -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

View file

@ -72,13 +72,13 @@ InitUSB()
CFRunLoopSourceRef runLoopSource;
SInt32 vendor, product;
int i;
//* To set up asynchronous notifications, create a notification port and
//* add its run loop event source to the program's run loop
notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
memset(notificationIterators, 0, sizeof(notificationIterators));
//* loop through all supported vendor/product pairs
@ -86,19 +86,19 @@ InitUSB()
//* Create our matching dictionary to find the Android device
//* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
if (!matchingDict) {
DBG("ERR: Couldn't create USB matching dictionary.\n");
return -1;
}
//* Set up two matching dictionaries, one for each product ID we support.
//* This will cause the kernel to notify us only if the vendor and product IDs match.
vendor = kSupportedDevices[i].vid;
product = kSupportedDevices[i].pid;
CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
//* Now set up two notifications: one to be called when a raw device
//* is first matched by the I/O Kit and another to be called when the
//* device is terminated.
@ -110,7 +110,7 @@ InitUSB()
AndroidDeviceAdded,
NULL,
&notificationIterators[i]);
//* Iterate over set of matching devices to access already-present devices
//* and to arm the notification
AndroidDeviceAdded(NULL, notificationIterators[i]);
@ -173,7 +173,7 @@ AndroidDeviceAdded(void *refCon, io_iterator_t iterator)
if (kr == kIOReturnSuccess && req.wLenDone > 0) {
int i, count;
// skip first word, and copy the rest to the serial string, changing shorts to bytes.
count = (req.wLenDone - 1) / 2;
for (i = 0; i < count; i++)
@ -401,8 +401,8 @@ void* RunLoopThread(void* unused)
currentRunLoop = 0;
for (i = 0; i < kSupportedDeviceCount; i++) {
IOObjectRelease(notificationIterators[i]);
}
IOObjectRelease(notificationIterators[i]);
}
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");

View file

@ -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
View 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
View 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 */

View file

@ -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))

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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)

View file

@ -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]);

View file

@ -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:
*

View 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 */

View file

@ -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

View file

@ -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,

View file

@ -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/*" },

View file

@ -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];
}

View file

@ -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

View file

@ -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
View 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 */

View file

@ -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]);

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;
}

View file

@ -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.

View file

@ -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
View 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 */

View file

@ -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;
}

View file

@ -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))

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -0,0 +1 @@
include $(all-subdir-makefiles)

View 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)

View 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;
}

View file

@ -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

View file

@ -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;

View file

@ -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
View 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
View 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

View file

@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
AutoMount.c \
ProcessKiller.c \
Server.c \
mountd.c
mountd.c \
ASEC.c
LOCAL_MODULE:= mountd

View file

@ -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");

View file

@ -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));
}
}
}

View file

@ -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
View 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 */

View file

@ -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);
}
}
}

View file

@ -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__

View file

@ -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)

View file

@ -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>

View file

@ -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;
}

View file

@ -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

View file

@ -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
}

View 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

View file

@ -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)