donut snapshot
diff --git a/NOTICE b/NOTICE
index 267a6aa..bb9c5f2 100644
--- a/NOTICE
+++ b/NOTICE
@@ -220,3 +220,54 @@
END OF TERMS AND CONDITIONS
+
+
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+and http://www.unicode.org/cldr/data/ . Unicode Software includes any
+source code published in the Unicode Standard or under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
+http://www.unicode.org/cldr/data/.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA
+FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY
+ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF
+THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY,
+DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed
+under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation (the
+"Data Files") or Unicode software and any associated documentation (the
+"Software") to deal in the Data Files or Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, and/or sell copies of the Data Files or Software,
+and to permit persons to whom the Data Files or Software are furnished to
+do so, provided that (a) the above copyright notice(s) and this permission
+notice appear with all copies of the Data Files or Software, (b) both the
+above copyright notice(s) and this permission notice appear in associated
+documentation, and (c) there is clear notice in each modified Data File
+or in the Software as well as in the documentation associated with the
+Data File(s) or Software that the data or software has been modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index f85ea9f..022fe5a 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -32,6 +32,7 @@
#include <media/AudioSystem.h>
#include "CameraService.h"
+#include <cutils/atomic.h>
#include <cutils/properties.h>
namespace android {
@@ -42,6 +43,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
+#include <signal.h>
}
// When you enable this, as well as DEBUG_REFS=1 and
@@ -63,6 +65,10 @@
static int debug_frame_cnt;
#endif
+static int getCallingPid() {
+ return IPCThreadState::self()->getCallingPid();
+}
+
// ----------------------------------------------------------------------------
void CameraService::instantiate() {
@@ -76,6 +82,7 @@
BnCameraService()
{
LOGI("CameraService started: pid=%d", getpid());
+ mUsers = 0;
}
CameraService::~CameraService()
@@ -87,72 +94,105 @@
sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
{
- LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
+ int callingPid = getCallingPid();
+ LOGD("CameraService::connect E (pid %d, client %p)", callingPid,
+ cameraClient->asBinder().get());
- Mutex::Autolock lock(mLock);
+ Mutex::Autolock lock(mServiceLock);
sp<Client> client;
if (mClient != 0) {
sp<Client> currentClient = mClient.promote();
if (currentClient != 0) {
sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
- // this is the same client reconnecting...
- LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get());
+ // This is the same client reconnecting...
+ LOGD("CameraService::connect X (pid %d, same client %p) is reconnecting...",
+ callingPid, cameraClient->asBinder().get());
return currentClient;
} else {
- // it's another client... reject it
- LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get());
+ // It's another client... reject it
+ LOGD("CameraService::connect X (pid %d, new client %p) rejected. "
+ "(old pid %d, old client %p)",
+ callingPid, cameraClient->asBinder().get(),
+ currentClient->mClientPid, currentCameraClient->asBinder().get());
+ if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) {
+ LOGD("The old client is dead!");
+ }
return client;
}
} else {
// can't promote, the previous client has died...
- LOGD("new client connecting, old reference was dangling...");
+ LOGD("New client (pid %d) connecting, old reference was dangling...",
+ callingPid);
mClient.clear();
}
}
+ if (mUsers > 0) {
+ LOGD("Still have client, rejected");
+ return client;
+ }
+
// create a new Client object
- client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
+ client = new Client(this, cameraClient, callingPid);
mClient = client;
#if DEBUG_CLIENT_REFERENCES
// Enable tracking for this object, and track increments and decrements of
// the refcount.
client->trackMe(true, true);
#endif
- LOGD("Connect X");
+ LOGD("CameraService::connect X");
return client;
}
void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
{
- // declar this outside the lock to make absolutely sure the
+ int callingPid = getCallingPid();
+
+ // Declare this outside the lock to make absolutely sure the
// destructor won't be called with the lock held.
sp<Client> client;
- Mutex::Autolock lock(mLock);
+ Mutex::Autolock lock(mServiceLock);
if (mClient == 0) {
// This happens when we have already disconnected.
- LOGV("mClient is null.");
+ LOGD("removeClient (pid %d): already disconnected", callingPid);
return;
}
- // Promote mClient. It should never fail because we're called from
- // a binder call, so someone has to have a strong reference.
+ // Promote mClient. It can fail if we are called from this path:
+ // Client::~Client() -> disconnect() -> removeClient().
client = mClient.promote();
if (client == 0) {
- LOGW("can't get a strong reference on mClient!");
+ LOGD("removeClient (pid %d): no more strong reference", callingPid);
mClient.clear();
return;
}
if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
// ugh! that's not our client!!
- LOGW("removeClient() called, but mClient doesn't match!");
+ LOGW("removeClient (pid %d): mClient doesn't match!", callingPid);
} else {
// okay, good, forget about mClient
mClient.clear();
}
+
+ LOGD("removeClient (pid %d) done", callingPid);
+}
+
+// The reason we need this count is a new CameraService::connect() request may
+// come in while the previous Client's destructor has not been run or is still
+// running. If the last strong reference of the previous Client is gone but
+// destructor has not been run, we should not allow the new Client to be created
+// because we need to wait for the previous Client to tear down the hardware
+// first.
+void CameraService::incUsers() {
+ android_atomic_inc(&mUsers);
+}
+
+void CameraService::decUsers() {
+ android_atomic_dec(&mUsers);
}
static sp<MediaPlayer> newMediaPlayer(const char *file)
@@ -177,7 +217,8 @@
CameraService::Client::Client(const sp<CameraService>& cameraService,
const sp<ICameraClient>& cameraClient, pid_t clientPid)
{
- LOGD("Client E constructor");
+ int callingPid = getCallingPid();
+ LOGD("Client::Client E (pid %d)", callingPid);
mCameraService = cameraService;
mCameraClient = cameraClient;
mClientPid = clientPid;
@@ -189,22 +230,28 @@
// Callback is disabled by default
mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
- LOGD("Client X constructor");
+ cameraService->incUsers();
+ LOGD("Client::Client X (pid %d)", callingPid);
}
status_t CameraService::Client::checkPid()
{
- if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
- LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get());
+ int callingPid = getCallingPid();
+ if (mClientPid == callingPid) return NO_ERROR;
+ LOGW("Attempt to use locked camera (client %p) from different process "
+ " (old pid %d, new pid %d)",
+ getCameraClient()->asBinder().get(), mClientPid, callingPid);
return -EBUSY;
}
status_t CameraService::Client::lock()
{
+ int callingPid = getCallingPid();
+ LOGD("lock from pid %d (mClientPid %d)", callingPid, mClientPid);
Mutex::Autolock _l(mLock);
// lock camera to this client if the the camera is unlocked
if (mClientPid == 0) {
- mClientPid = IPCThreadState::self()->getCallingPid();
+ mClientPid = callingPid;
return NO_ERROR;
}
// returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
@@ -213,13 +260,14 @@
status_t CameraService::Client::unlock()
{
+ int callingPid = getCallingPid();
+ LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);
Mutex::Autolock _l(mLock);
// allow anyone to use camera
- LOGV("unlock (%p)", getCameraClient()->asBinder().get());
status_t result = checkPid();
if (result == NO_ERROR) {
mClientPid = 0;
-
+ LOGD("clear mCameraClient (pid %d)", callingPid);
// we need to remove the reference so that when app goes
// away, the reference count goes to 0.
mCameraClient.clear();
@@ -229,15 +277,17 @@
status_t CameraService::Client::connect(const sp<ICameraClient>& client)
{
+ int callingPid = getCallingPid();
+
// connect a new process to the camera
- LOGV("connect (%p)", client->asBinder().get());
+ LOGD("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get());
// I hate this hack, but things get really ugly when the media recorder
// service is handing back the camera to the app. The ICameraClient
// destructor will be called during the same IPC, making it look like
// the remote client is trying to disconnect. This hack temporarily
// sets the mClientPid to an invalid pid to prevent the hardware from
- // being torn down.
+ // being torn down.
{
// hold a reference to the old client or we will deadlock if the client is
@@ -245,25 +295,30 @@
sp<ICameraClient> oldClient;
{
Mutex::Autolock _l(mLock);
- if (mClientPid != 0) {
- LOGW("Tried to connect to locked camera");
+ if (mClientPid != 0 && checkPid() != NO_ERROR) {
+ LOGW("Tried to connect to locked camera (old pid %d, new pid %d)",
+ mClientPid, callingPid);
return -EBUSY;
}
oldClient = mCameraClient;
// did the client actually change?
- if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+ if (client->asBinder() == mCameraClient->asBinder()) {
+ LOGD("Connect to the same client");
+ return NO_ERROR;
+ }
mCameraClient = client;
mClientPid = -1;
mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
- LOGV("connect new process (%d) to existing camera client", mClientPid);
+ LOGD("Connect to the new client (pid %d, client %p)",
+ callingPid, mCameraClient->asBinder().get());
}
}
// the old client destructor is called when oldClient goes out of scope
// now we set the new PID to lock the interface again
- mClientPid = IPCThreadState::self()->getCallingPid();
+ mClientPid = callingPid;
return NO_ERROR;
}
@@ -280,8 +335,11 @@
CameraService::Client::~Client()
{
+ int callingPid = getCallingPid();
+
// tear down client
- LOGD("Client (%p) E destructor", getCameraClient()->asBinder().get());
+ LOGD("Client::~Client E (pid %d, client %p)",
+ callingPid, getCameraClient()->asBinder().get());
if (mSurface != 0 && !mUseOverlay) {
#if HAVE_ANDROID_OS
pthread_t thr;
@@ -307,49 +365,59 @@
}
// make sure we tear down the hardware
- mClientPid = IPCThreadState::self()->getCallingPid();
+ mClientPid = callingPid;
disconnect();
- LOGD("Client X destructor");
+ LOGD("Client::~Client X (pid %d)", mClientPid);
}
void CameraService::Client::disconnect()
{
- LOGD("Client (%p) E disconnect from (%d)",
- getCameraClient()->asBinder().get(),
- IPCThreadState::self()->getCallingPid());
+ int callingPid = getCallingPid();
+
+ LOGD("Client::disconnect() E (pid %d client %p)",
+ callingPid, getCameraClient()->asBinder().get());
+
Mutex::Autolock lock(mLock);
if (mClientPid <= 0) {
- LOGV("camera is unlocked, don't tear down hardware");
+ LOGD("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
return;
}
if (checkPid() != NO_ERROR) {
- LOGV("Different client - don't disconnect");
+ LOGD("Different client - don't disconnect");
return;
}
- mCameraService->removeClient(mCameraClient);
- if (mHardware != 0) {
- LOGV("hardware teardown");
- // Before destroying mHardware, we must make sure it's in the
- // idle state.
- mHardware->stopPreview();
- // Cancel all picture callbacks.
- mHardware->cancelPicture(true, true, true);
- // Release the hardware resources.
- mHardware->release();
- }
+ // Make sure disconnect() is done once and once only, whether it is called
+ // from the user directly, or called by the destructor.
+ if (mHardware == 0) return;
+
+ LOGD("hardware teardown");
+ // Before destroying mHardware, we must make sure it's in the
+ // idle state.
+ mHardware->stopPreview();
+ // Cancel all picture callbacks.
+ mHardware->cancelPicture(true, true, true);
+ // Release the hardware resources.
+ mHardware->release();
mHardware.clear();
- LOGD("Client X disconnect");
+
+ mCameraService->removeClient(mCameraClient);
+ mCameraService->decUsers();
+
+ LOGD("Client::disconnect() X (pid %d)", callingPid);
}
// pass the buffered ISurface to the camera service
status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
{
- LOGD("setPreviewDisplay(%p)", surface.get());
+ LOGD("setPreviewDisplay(%p) (pid %d)",
+ ((surface == NULL) ? NULL : surface.get()), getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPid();
if (result != NO_ERROR) return result;
+
Mutex::Autolock surfaceLock(mSurfaceLock);
+ result = NO_ERROR;
// asBinder() is safe on NULL (returns NULL)
if (surface->asBinder() != mSurface->asBinder()) {
if (mSurface != 0 && !mUseOverlay) {
@@ -357,24 +425,35 @@
mSurface->unregisterBuffers();
}
mSurface = surface;
+ // If preview has been already started, set overlay or register preview
+ // buffers now.
+ if (mHardware->previewEnabled()) {
+ if (mUseOverlay) {
+ result = setOverlay();
+ } else if (mSurface != 0) {
+ result = registerPreviewBuffers();
+ }
+ }
}
- return NO_ERROR;
+ return result;
}
// set the preview callback flag to affect how the received frames from
// preview are handled.
void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
{
- LOGV("setPreviewCallbackFlag");
+ LOGV("setPreviewCallbackFlag (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
mPreviewCallbackFlag = callback_flag;
}
-// start preview mode, must call setPreviewDisplay first
+// start preview mode
status_t CameraService::Client::startCameraMode(camera_mode mode)
{
- LOGD("startCameraMode(%d)", mode);
+ int callingPid = getCallingPid();
+
+ LOGD("startCameraMode(%d) (pid %d)", mode, callingPid);
/* we cannot call into mHardware with mLock held because
* mHardware has callbacks onto us which acquire this lock
@@ -389,23 +468,25 @@
return INVALID_OPERATION;
}
- if (mSurface == 0) {
- LOGE("setPreviewDisplay must be called before startCameraMode!");
- return INVALID_OPERATION;
- }
-
switch(mode) {
case CAMERA_RECORDING_MODE:
+ if (mSurface == 0) {
+ LOGE("setPreviewDisplay must be called before startRecordingMode.");
+ return INVALID_OPERATION;
+ }
return startRecordingMode();
default: // CAMERA_PREVIEW_MODE
+ if (mSurface == 0) {
+ LOGD("mSurface is not set yet.");
+ }
return startPreviewMode();
}
}
status_t CameraService::Client::startRecordingMode()
{
- LOGV("startRecordingMode");
+ LOGD("startRecordingMode (pid %d)", getCallingPid());
status_t ret = UNKNOWN_ERROR;
@@ -431,9 +512,65 @@
return ret;
}
+status_t CameraService::Client::setOverlay()
+{
+ LOGD("setOverlay");
+ int w, h;
+ CameraParameters params(mHardware->getParameters());
+ params.getPreviewSize(&w, &h);
+
+ const char *format = params.getPreviewFormat();
+ int fmt;
+ if (!strcmp(format, "yuv422i"))
+ fmt = OVERLAY_FORMAT_YCbCr_422_I;
+ else if (!strcmp(format, "rgb565"))
+ fmt = OVERLAY_FORMAT_RGB_565;
+ else {
+ LOGE("Invalid preview format for overlays");
+ return -EINVAL;
+ }
+
+ status_t ret = NO_ERROR;
+ if (mSurface != 0) {
+ sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
+ ret = mHardware->setOverlay(new Overlay(ref));
+ } else {
+ ret = mHardware->setOverlay(NULL);
+ }
+ if (ret != NO_ERROR) {
+ LOGE("mHardware->setOverlay() failed with status %d\n", ret);
+ }
+ return ret;
+}
+
+status_t CameraService::Client::registerPreviewBuffers()
+{
+ int w, h;
+ CameraParameters params(mHardware->getParameters());
+ params.getPreviewSize(&w, &h);
+
+ uint32_t transform = 0;
+ if (params.getOrientation() ==
+ CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
+ LOGV("portrait mode");
+ transform = ISurface::BufferHeap::ROT_90;
+ }
+ ISurface::BufferHeap buffers(w, h, w, h,
+ PIXEL_FORMAT_YCbCr_420_SP,
+ transform,
+ 0,
+ mHardware->getPreviewHeap());
+
+ status_t ret = mSurface->registerBuffers(buffers);
+ if (ret != NO_ERROR) {
+ LOGE("registerBuffers failed with status %d", ret);
+ }
+ return ret;
+}
+
status_t CameraService::Client::startPreviewMode()
{
- LOGV("startPreviewMode");
+ LOGD("startPreviewMode (pid %d)", getCallingPid());
// if preview has been enabled, nothing needs to be done
if (mHardware->previewEnabled()) {
@@ -444,55 +581,24 @@
#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
debug_frame_cnt = 0;
#endif
- status_t ret = UNKNOWN_ERROR;
- int w, h;
- CameraParameters params(mHardware->getParameters());
- params.getPreviewSize(&w, &h);
+ status_t ret = NO_ERROR;
if (mUseOverlay) {
- const char *format = params.getPreviewFormat();
- int fmt;
- LOGD("Use Overlays");
- if (!strcmp(format, "yuv422i"))
- fmt = OVERLAY_FORMAT_YCbCr_422_I;
- else if (!strcmp(format, "rgb565"))
- fmt = OVERLAY_FORMAT_RGB_565;
- else {
- LOGE("Invalid preview format for overlays");
- return -EINVAL;
+ // If preview display has been set, set overlay now.
+ if (mSurface != 0) {
+ ret = setOverlay();
}
- sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
- ret = mHardware->setOverlay(new Overlay(ref));
- if (ret != NO_ERROR) {
- LOGE("mHardware->setOverlay() failed with status %d\n", ret);
- return ret;
- }
+ if (ret != NO_ERROR) return ret;
ret = mHardware->startPreview(NULL, mCameraService.get());
- if (ret != NO_ERROR)
- LOGE("mHardware->startPreview() failed with status %d\n", ret);
-
} else {
ret = mHardware->startPreview(previewCallback,
mCameraService.get());
- if (ret == NO_ERROR) {
-
- mSurface->unregisterBuffers();
-
- uint32_t transform = 0;
- if (params.getOrientation() ==
- CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
- LOGV("portrait mode");
- transform = ISurface::BufferHeap::ROT_90;
- }
- ISurface::BufferHeap buffers(w, h, w, h,
- PIXEL_FORMAT_YCbCr_420_SP,
- transform,
- 0,
- mHardware->getPreviewHeap());
-
- mSurface->registerBuffers(buffers);
- } else {
- LOGE("mHardware->startPreview() failed with status %d", ret);
+ if (ret != NO_ERROR) return ret;
+ // If preview display has been set, register preview buffers now.
+ if (mSurface != 0) {
+ // Unregister here because the surface registered with raw heap.
+ mSurface->unregisterBuffers();
+ ret = registerPreviewBuffers();
}
}
return ret;
@@ -500,11 +606,15 @@
status_t CameraService::Client::startPreview()
{
+ LOGD("startPreview (pid %d)", getCallingPid());
+
return startCameraMode(CAMERA_PREVIEW_MODE);
}
status_t CameraService::Client::startRecording()
{
+ LOGD("startRecording (pid %d)", getCallingPid());
+
if (mMediaPlayerBeep.get() != NULL) {
mMediaPlayerBeep->seekTo(0);
mMediaPlayerBeep->start();
@@ -515,7 +625,7 @@
// stop preview mode
void CameraService::Client::stopPreview()
{
- LOGD("stopPreview()");
+ LOGD("stopPreview (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
@@ -537,7 +647,7 @@
// stop recording mode
void CameraService::Client::stopRecording()
{
- LOGV("stopRecording()");
+ LOGD("stopRecording (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
@@ -552,15 +662,13 @@
mMediaPlayerBeep->start();
}
mHardware->stopRecording();
- LOGV("stopRecording(), hardware stopped OK");
+ LOGD("stopRecording(), hardware stopped OK");
mPreviewBuffer.clear();
}
// release a recording frame
void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
{
- LOGV("releaseRecordingFrame()");
-
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
@@ -592,7 +700,7 @@
sp<Client> client = 0;
CameraService *service = static_cast<CameraService*>(user);
if (service != NULL) {
- Mutex::Autolock ourLock(service->mLock);
+ Mutex::Autolock ourLock(service->mServiceLock);
if (service->mClient != 0) {
client = service->mClient.promote();
if (client == 0) {
@@ -704,7 +812,7 @@
// take a picture - image is returned in callback
status_t CameraService::Client::autoFocus()
{
- LOGV("autoFocus");
+ LOGD("autoFocus (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPid();
@@ -722,7 +830,7 @@
// take a picture - image is returned in callback
status_t CameraService::Client::takePicture()
{
- LOGD("takePicture");
+ LOGD("takePicture (pid %d)", getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPid();
@@ -920,6 +1028,7 @@
void CameraService::Client::postShutter()
{
+ LOGD("postShutter");
mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
}
@@ -1029,12 +1138,12 @@
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
snprintf(buffer, SIZE, "Permission Denial: "
"can't dump CameraService from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
+ getCallingPid(),
IPCThreadState::self()->getCallingUid());
result.append(buffer);
write(fd, result.string(), result.size());
} else {
- AutoMutex lock(&mLock);
+ AutoMutex lock(&mServiceLock);
if (mClient != 0) {
sp<Client> currentClient = mClient.promote();
sprintf(buffer, "Client (%p) PID: %d\n",
@@ -1052,8 +1161,6 @@
}
-#if DEBUG_HEAP_LEAKS
-
#define CHECK_INTERFACE(interface, data, reply) \
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
LOGW("Call incorrectly routed to " #interface); \
@@ -1085,6 +1192,7 @@
status_t err = BnCameraService::onTransact(code, data, reply, flags);
+#if DEBUG_HEAP_LEAKS
LOGD("+++ onTransact err %d code %d", err, code);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
@@ -1120,9 +1228,9 @@
break;
}
}
+#endif // DEBUG_HEAP_LEAKS
+
return err;
}
-#endif // DEBUG_HEAP_LEAKS
-
}; // namespace android
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 6752f26..0f07673 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -58,10 +58,8 @@
void removeClient(const sp<ICameraClient>& cameraClient);
-#if DEBUG_HEAP_LEAKS
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-#endif
private:
@@ -159,6 +157,8 @@
status_t startCameraMode(camera_mode mode);
status_t startPreviewMode();
status_t startRecordingMode();
+ status_t setOverlay();
+ status_t registerPreviewBuffers();
// Ensures atomicity among the public methods
mutable Mutex mLock;
@@ -196,7 +196,12 @@
CameraService();
virtual ~CameraService();
- mutable Mutex mLock;
+ // We use a count for number of clients (shoule only be 0 or 1).
+ volatile int32_t mUsers;
+ virtual void incUsers();
+ virtual void decUsers();
+
+ mutable Mutex mServiceLock;
wp<Client> mClient;
#if DEBUG_HEAP_LEAKS
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
new file mode 100644
index 0000000..3daf44e
--- /dev/null
+++ b/cmds/keystore/Android.mk
@@ -0,0 +1,22 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ netkeystore.c keymgmt.c
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, system-core)/cutils \
+ external/openssl/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils libssl
+
+LOCAL_STATIC_LIBRARIES :=
+
+LOCAL_MODULE:= keystore
+
+include $(BUILD_EXECUTABLE)
+
+endif # !simulator))
diff --git a/cmds/keystore/certtool.h b/cmds/keystore/certtool.h
new file mode 100644
index 0000000..aefad66
--- /dev/null
+++ b/cmds/keystore/certtool.h
@@ -0,0 +1,91 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef __CERTTOOL_H__
+#define __CERTTOOL_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <cutils/sockets.h>
+#include <cutils/log.h>
+
+#include "common.h"
+#include "netkeystore.h"
+
+#define CERT_NAME_LEN (2 * MAX_KEY_NAME_LENGTH + 2)
+
+/*
+ * The specific function 'get_cert' is used in daemons to get the key value
+ * from keystore. Caller should allocate the buffer and the length of the buffer
+ * should be MAX_KEY_VALUE_LENGTH.
+ */
+static inline int get_cert(const char *certname, unsigned char *value, int *size)
+{
+ int count, fd, ret = -1;
+ LPC_MARSHAL cmd;
+ char delimiter[] = "_";
+ char *namespace, *keyname;
+ char *context = NULL;
+ char cname[CERT_NAME_LEN];
+
+ if ((certname == NULL) || (value == NULL)) {
+ LOGE("get_cert: certname or value is null\n");
+ return -1;
+ }
+
+ if (strlcpy(cname, certname, CERT_NAME_LEN) >= CERT_NAME_LEN) {
+ LOGE("get_cert: keyname is too long\n");
+ return -1;
+ }
+
+ fd = socket_local_client(SOCKET_PATH,
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (fd == -1) {
+ LOGE("Keystore service is not up and running.\n");
+ return -1;
+ }
+
+ cmd.opcode = GET;
+ if (((namespace = strtok_r(cname, delimiter, &context)) == NULL) ||
+ ((keyname = strtok_r(NULL, delimiter, &context)) == NULL)) {
+ goto err;
+ }
+ if ((cmd.len = snprintf((char*)cmd.data, BUFFER_MAX, "%s %s", namespace, keyname))
+ > (2 * MAX_KEY_NAME_LENGTH + 1)) goto err;
+
+ if (write_marshal(fd, &cmd)) {
+ LOGE("Incorrect command or command line is too long.\n");
+ goto err;
+ }
+ if (read_marshal(fd, &cmd)) {
+ LOGE("Failed to read the result.\n");
+ goto err;
+ }
+
+ // copy the result if succeeded.
+ if (!cmd.retcode && cmd.len <= BUFFER_MAX) {
+ memcpy(value, cmd.data, cmd.len);
+ ret = 0;
+ *size = cmd.len;
+ }
+err:
+ close(fd);
+ return ret;
+}
+
+#endif
diff --git a/cmds/keystore/common.h b/cmds/keystore/common.h
new file mode 100644
index 0000000..a18114e
--- /dev/null
+++ b/cmds/keystore/common.h
@@ -0,0 +1,60 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#define SOCKET_PATH "keystore"
+#define KEYSTORE_DIR "/data/misc/keystore/"
+
+#define READ_TIMEOUT 3
+#define MAX_KEY_NAME_LENGTH 64
+#define MAX_NAMESPACE_LENGTH MAX_KEY_NAME_LENGTH
+#define MAX_KEY_VALUE_LENGTH 4096
+
+#define BUFFER_MAX MAX_KEY_VALUE_LENGTH
+
+typedef enum {
+ BOOTUP,
+ UNINITIALIZED,
+ LOCKED,
+ UNLOCKED,
+} KEYSTORE_STATE;
+
+typedef enum {
+ LOCK,
+ UNLOCK,
+ PASSWD,
+ GETSTATE,
+ LISTKEYS,
+ GET,
+ PUT,
+ REMOVE,
+ RESET,
+ MAX_OPCODE
+} KEYSTORE_OPCODE;
+
+typedef struct {
+ uint32_t len;
+ union {
+ uint32_t opcode;
+ uint32_t retcode;
+ };
+ unsigned char data[BUFFER_MAX + 1];
+} LPC_MARSHAL;
+
+#endif
diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c
new file mode 100644
index 0000000..66edd56
--- /dev/null
+++ b/cmds/keystore/keymgmt.c
@@ -0,0 +1,372 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <cutils/log.h>
+
+#include "common.h"
+#include "keymgmt.h"
+
+static int retry_count = 0;
+static unsigned char iv[IV_LEN];
+static KEYSTORE_STATE state = BOOTUP;
+static AES_KEY encryptKey, decryptKey;
+
+inline void unlock_keystore(unsigned char *master_key)
+{
+ AES_set_encrypt_key(master_key, AES_KEY_LEN, &encryptKey);
+ AES_set_decrypt_key(master_key, AES_KEY_LEN, &decryptKey);
+ memset(master_key, 0, sizeof(master_key));
+ state = UNLOCKED;
+}
+
+inline void lock_keystore()
+{
+ memset(&encryptKey, 0 , sizeof(AES_KEY));
+ memset(&decryptKey, 0 , sizeof(AES_KEY));
+ state = LOCKED;
+}
+
+inline void get_encrypt_key(char *passwd, AES_KEY *key)
+{
+ unsigned char user_key[USER_KEY_LEN];
+ gen_key(passwd, user_key, USER_KEY_LEN);
+ AES_set_encrypt_key(user_key, AES_KEY_LEN, key);
+}
+
+inline void get_decrypt_key(char *passwd, AES_KEY *key)
+{
+ unsigned char user_key[USER_KEY_LEN];
+ gen_key(passwd, user_key, USER_KEY_LEN);
+ AES_set_decrypt_key(user_key, AES_KEY_LEN, key);
+}
+
+static int gen_random_blob(unsigned char *key, int size)
+{
+ int ret = 0;
+ int fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1) return -1;
+ if (read(fd, key, size) != size) ret = -1;
+ close(fd);
+ return ret;
+}
+
+static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob,
+ const char *keyfile)
+{
+ int size, fd, ret = -1;
+ unsigned char enc_blob[MAX_BLOB_LEN];
+
+ char tmpfile[KEYFILE_LEN];
+ strcpy(tmpfile, keyfile);
+ strcat(tmpfile, ".tmp");
+
+ // prepare the blob
+ memcpy(blob->iv, iv, IV_LEN);
+ blob->blob_size = get_blob_size(blob);
+ memcpy(enc_blob, blob->blob, blob->blob_size);
+ AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob,
+ blob->blob_size, enc_key, iv, AES_ENCRYPT);
+ // write to keyfile
+ size = data_blob_size(blob);
+ if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1;
+ if (write(fd, blob, size) == size) ret = 0;
+ close(fd);
+ if (!ret) {
+ unlink(keyfile);
+ rename(tmpfile, keyfile);
+ chmod(keyfile, 0440);
+ }
+ return ret;
+}
+
+static int load_n_decrypt(const char *keyname, const char *keyfile,
+ AES_KEY *key, DATA_BLOB *blob)
+{
+ int fd, ret = -1;
+ if ((fd = open(keyfile, O_RDONLY)) == -1) return -1;
+ // get the encrypted blob and iv
+ if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) ||
+ (read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) ||
+ (blob->blob_size > MAX_BLOB_LEN)) {
+ goto err;
+ } else {
+ unsigned char enc_blob[MAX_BLOB_LEN];
+ if (read(fd, enc_blob, blob->blob_size) !=
+ (int) blob->blob_size) goto err;
+ // decrypt the blob
+ AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob,
+ blob->blob_size, key, blob->iv, AES_DECRYPT);
+ if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0;
+ }
+err:
+ close(fd);
+ return ret;
+}
+
+static int store_master_key(char *upasswd, unsigned char *master_key)
+{
+ AES_KEY key;
+ DATA_BLOB blob;
+
+ // prepare the blob
+ strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN);
+ blob.value_size = USER_KEY_LEN;
+ memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN);
+
+ // generate the encryption key
+ get_encrypt_key(upasswd, &key);
+ return encrypt_n_save(&key, &blob, MASTER_KEY);
+}
+
+static int get_master_key(char *upasswd, unsigned char *master_key)
+{
+ AES_KEY key;
+ int size, ret = 0;
+ DATA_BLOB blob;
+
+ get_decrypt_key(upasswd, &key);
+ ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob);
+ if (!ret) memcpy(master_key, blob.value, blob.value_size);
+ return ret;
+}
+
+static int create_master_key(char *upasswd)
+{
+ int ret;
+ unsigned char mpasswd[AES_KEY_LEN];
+ unsigned char master_key[USER_KEY_LEN];
+
+ gen_random_blob(mpasswd, AES_KEY_LEN);
+ gen_key((char*)mpasswd, master_key, USER_KEY_LEN);
+ if ((ret = store_master_key(upasswd, master_key)) == 0) {
+ unlock_keystore(master_key);
+ }
+ memset(master_key, 0, USER_KEY_LEN);
+ memset(mpasswd, 0, AES_KEY_LEN);
+
+ return ret;
+}
+
+static int change_passwd(char *data)
+{
+ unsigned char master_key[USER_KEY_LEN];
+ char *old_pass, *new_pass = NULL, *p, *delimiter=" ";
+ int ret, count = 0;
+ char *context = NULL;
+
+ old_pass = p = strtok_r(data, delimiter, &context);
+ while (p != NULL) {
+ count++;
+ new_pass = p;
+ p = strtok_r(NULL, delimiter, &context);
+ }
+ if (count != 2) return -1;
+ if (strlen(new_pass) < MIN_PASSWD_LENGTH) return -1;
+ if ((ret = get_master_key(old_pass, master_key)) == 0) {
+ ret = store_master_key(new_pass, master_key);
+ retry_count = 0;
+ } else {
+ ret = MAX_RETRY_COUNT - ++retry_count;
+ if (ret == 0) {
+ retry_count = 0;
+ LOGE("passwd:reach max retry count, reset the keystore now.");
+ reset_keystore();
+ return -1;
+ }
+
+ }
+ return ret;
+}
+
+int remove_key(const char *namespace, const char *keyname)
+{
+ char keyfile[KEYFILE_LEN];
+
+ if (state != UNLOCKED) return -state;
+ sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
+ return unlink(keyfile);
+}
+
+int put_key(const char *namespace, const char *keyname,
+ unsigned char *data, int size)
+{
+ DATA_BLOB blob;
+ uint32_t real_size;
+ char keyfile[KEYFILE_LEN];
+
+ if (state != UNLOCKED) {
+ LOGE("Can not store key with current state %d\n", state);
+ return -state;
+ }
+ sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
+ // flatten the args
+ strcpy(blob.keyname, keyname);
+ blob.value_size = size;
+ memcpy(blob.value, data, size);
+ return encrypt_n_save(&encryptKey, &blob, keyfile);
+}
+
+int get_key(const char *namespace, const char *keyname,
+ unsigned char *data, int *size)
+{
+ int ret;
+ DATA_BLOB blob;
+ uint32_t blob_size;
+ char keyfile[KEYFILE_LEN];
+
+ if (state != UNLOCKED) {
+ LOGE("Can not retrieve key value with current state %d\n", state);
+ return -state;
+ }
+ sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
+ ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
+ if (!ret) {
+ if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) {
+ ret = -1;
+ } else {
+ *size = blob.value_size;
+ memcpy(data, blob.value, *size);
+ }
+ }
+ return ret;
+}
+
+int list_keys(const char *namespace, char reply[BUFFER_MAX])
+{
+ DIR *d;
+ struct dirent *de;
+
+ if (state != UNLOCKED) {
+ LOGE("Can not list key with current state %d\n", state);
+ return -1;
+ }
+
+ if (!namespace || ((d = opendir("."))) == NULL) {
+ LOGE("cannot open keystore dir or namespace is null\n");
+ return -1;
+ }
+ while ((de = readdir(d))) {
+ char *prefix, *name, *keyfile = de->d_name;
+ char *context = NULL;
+
+ if (de->d_type != DT_REG) continue;
+ if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context))
+ == NULL) continue;
+ if (strcmp(prefix, namespace)) continue;
+ if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue;
+ // append the key name into reply
+ if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX);
+ if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) {
+ LOGE("too many files under keystore directory\n");
+ return -1;
+ }
+ }
+ closedir(d);
+ return 0;
+}
+
+int passwd(char *data)
+{
+ if (state == UNINITIALIZED) {
+ if (strchr(data, ' ')) return -1;
+ if (strlen(data) < MIN_PASSWD_LENGTH) return -1;
+ return create_master_key(data);
+ }
+ return change_passwd(data);
+}
+
+int lock()
+{
+ switch(state) {
+ case UNLOCKED:
+ lock_keystore();
+ case LOCKED:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+int unlock(char *passwd)
+{
+ unsigned char master_key[USER_KEY_LEN];
+ int ret = get_master_key(passwd, master_key);
+ if (!ret) {
+ unlock_keystore(master_key);
+ retry_count = 0;
+ } else {
+ ret = MAX_RETRY_COUNT - ++retry_count;
+ if (ret == 0) {
+ retry_count = 0;
+ LOGE("unlock:reach max retry count, reset the keystore now.");
+ reset_keystore();
+ return -1;
+ }
+ }
+ return ret;
+}
+
+KEYSTORE_STATE get_state()
+{
+ return state;
+}
+
+int reset_keystore()
+{
+ DIR *d;
+ struct dirent *de;
+
+ if ((d = opendir(".")) == NULL) {
+ LOGE("cannot open keystore dir\n");
+ return -1;
+ }
+ while ((de = readdir(d))) unlink(de->d_name);
+ closedir(d);
+ state = UNINITIALIZED;
+ LOGI("keystore is reset.");
+ return 0;
+}
+
+int init_keystore(const char *dir)
+{
+ int fd;
+
+ if (!dir) mkdir(dir, 0770);
+ if (!dir || chdir(dir)) {
+ LOGE("Can not open/create the keystore directory %s\n",
+ dir ? dir : "(null)");
+ return -1;
+ }
+ gen_random_blob(iv, IV_LEN);
+ if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) {
+ state = UNINITIALIZED;
+ return 0;
+ }
+ close(fd);
+ state = LOCKED;
+ return 0;
+}
diff --git a/cmds/keystore/keymgmt.h b/cmds/keystore/keymgmt.h
new file mode 100644
index 0000000..0e928db
--- /dev/null
+++ b/cmds/keystore/keymgmt.h
@@ -0,0 +1,82 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef __KEYMGMT_H__
+#define __KEYMGMT_H__
+
+#define MASTER_KEY_TAG "master_key"
+#define MASTER_KEY ".keymaster"
+#define MAX_PATH_LEN 128
+#define SALT "Android Keystore 0.1"
+#define NAME_DELIMITER "_"
+#define KEYFILE_NAME "%s"NAME_DELIMITER"%s"
+#define KEYGEN_ITER 1024
+#define AES_KEY_LEN 128
+#define USER_KEY_LEN (AES_KEY_LEN/8)
+#define IV_LEN USER_KEY_LEN
+#define MAX_RETRY_COUNT 6
+#define MIN_PASSWD_LENGTH 8
+
+#define gen_key(passwd, key, len) \
+ PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), \
+ (unsigned char*)SALT, \
+ strlen(SALT), KEYGEN_ITER, \
+ len, key)
+
+#define KEYFILE_LEN MAX_NAMESPACE_LENGTH + MAX_KEY_NAME_LENGTH + 6
+
+#define get_blob_size(blob) \
+ (((blob->value_size + sizeof(uint32_t) + MAX_KEY_NAME_LENGTH \
+ + USER_KEY_LEN - 1) / USER_KEY_LEN) * USER_KEY_LEN)
+
+#define MAX_BLOB_LEN ((MAX_KEY_VALUE_LENGTH + MAX_KEY_NAME_LENGTH + \
+ sizeof(uint32_t) + USER_KEY_LEN - 1) / USER_KEY_LEN)\
+ * USER_KEY_LEN
+
+#define data_blob_size(blob) USER_KEY_LEN + sizeof(uint32_t) + blob->blob_size
+
+typedef struct {
+ unsigned char iv[USER_KEY_LEN];
+ uint32_t blob_size;
+ union {
+ unsigned char blob[1];
+ struct {
+ uint32_t value_size;
+ char keyname[MAX_KEY_NAME_LENGTH];
+ unsigned char value[MAX_KEY_VALUE_LENGTH];
+ } __attribute__((packed));
+ };
+} DATA_BLOB;
+
+typedef struct {
+ char tag[USER_KEY_LEN];
+ unsigned char master_key[USER_KEY_LEN];
+} MASTER_BLOB;
+
+int put_key(const char *namespace, const char *keyname,
+ unsigned char *data, int size);
+int get_key(const char *namespace, const char *keyname,
+ unsigned char *data, int *size);
+int remove_key(const char *namespace, const char *keyname);
+int list_keys(const char *namespace, char reply[BUFFER_MAX]);
+int passwd(char *data);
+int lock();
+int unlock(char *passwd);
+KEYSTORE_STATE get_state();
+int reset_keystore();
+int init_keystore(const char *dir);
+
+#endif
diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h
new file mode 100644
index 0000000..a7fd9a5
--- /dev/null
+++ b/cmds/keystore/keystore_get.h
@@ -0,0 +1,53 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef __KEYSTORE_GET_H__
+#define __KEYSTORE_GET_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "certtool.h"
+
+/* This function is provided to native components to get values from keystore.
+ * Users are required to link against libcutils. If something goes wrong, NULL
+ * is returned. Otherwise it returns the value in dynamically allocated memory
+ * and sets the size if the pointer is not NULL. One can release the memory by
+ * calling free(). */
+static char *keystore_get(char *key, int *size)
+{
+ char buffer[MAX_KEY_VALUE_LENGTH];
+ char *value;
+ int length;
+
+ if (get_cert(key, (unsigned char *)buffer, &length) != 0) {
+ return NULL;
+ }
+ value = malloc(length + 1);
+ if (!value) {
+ return NULL;
+ }
+ memcpy(value, buffer, length);
+ value[length] = 0;
+ if (size) {
+ *size = length;
+ }
+ return value;
+}
+
+#endif
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
new file mode 100644
index 0000000..eac455e
--- /dev/null
+++ b/cmds/keystore/netkeystore.c
@@ -0,0 +1,410 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "keystore"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <utime.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <private/android_filesystem_config.h>
+
+#include <cutils/sockets.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "netkeystore.h"
+#include "keymgmt.h"
+
+#define CMD_PUT_WITH_FILE "putfile"
+
+typedef void CMD_FUNC(LPC_MARSHAL *cmd, LPC_MARSHAL *reply);
+
+struct cmdinfo {
+ const char *name;
+ CMD_FUNC *func;
+};
+
+static CMD_FUNC do_lock;
+static CMD_FUNC do_unlock;
+static CMD_FUNC do_passwd;
+static CMD_FUNC do_get_state;;
+static CMD_FUNC do_listkeys;
+static CMD_FUNC do_get_key;
+static CMD_FUNC do_put_key;
+static CMD_FUNC do_remove_key;
+static CMD_FUNC do_reset_keystore;
+
+#define str(x) #x
+
+struct cmdinfo cmds[] = {
+ { str(LOCK), do_lock },
+ { str(UNLOCK), do_unlock },
+ { str(PASSWD), do_passwd },
+ { str(GETSTATE), do_get_state },
+ { str(LISTKEYS), do_listkeys },
+ { str(GET), do_get_key },
+ { str(PUT), do_put_key },
+ { str(REMOVE), do_remove_key },
+ { str(RESET), do_reset_keystore },
+};
+
+static struct ucred cr;
+
+static int check_get_perm(int uid)
+{
+ if (uid == AID_WIFI || uid == AID_VPN) return 0;
+ return -1;
+}
+
+static int check_reset_perm(int uid)
+{
+ if (uid == AID_SYSTEM) return 0;
+ return -1;
+}
+
+static int parse_keyname(char *name, uint32_t len,
+ char *namespace, char *keyname)
+{
+ int count = 0;
+ char *c = namespace, *p = namespace, *t = name;
+
+ if (!name || !namespace || !keyname) return -1;
+ while (t < name + len && (*t != 0)) {
+ if (*t == ' ') {
+ if (c == keyname) return -1;
+ *p = count = 0;
+ c = p = keyname;
+ t++;
+ } else {
+ if (!isalnum(*t)) return -1;
+ *p++ = *t++;
+ // also check if the keyname/namespace is too long.
+ if (count++ == MAX_KEY_NAME_LENGTH) return -1;
+ }
+ }
+ *p = 0;
+ return 0;
+}
+
+// args of passwd():
+// firstPassword - for the first time
+// oldPassword newPassword - for changing the password
+static void do_passwd(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ reply->retcode = passwd((char*)cmd->data);
+}
+
+// args of lock():
+// no argument
+static void do_lock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ reply->retcode = lock();
+}
+
+// args of unlock():
+// password
+static void do_unlock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ reply->retcode = unlock((char*)cmd->data);
+}
+
+// args of get_state():
+// no argument
+static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ reply->retcode = get_state();
+}
+
+// args of listkeys():
+// namespace
+static void do_listkeys(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ reply->retcode = list_keys((const char*)cmd->data, (char*)reply->data);
+ if (!reply->retcode) reply->len = strlen((char*)reply->data);
+}
+
+// args of get():
+// namespace keyname
+static void do_get_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ char namespace[MAX_KEY_NAME_LENGTH];
+ char keyname[MAX_KEY_NAME_LENGTH];
+
+ if (check_get_perm(cr.uid)) {
+ LOGE("uid %d doesn't have the permission to get key value\n", cr.uid);
+ reply->retcode = -1;
+ return;
+ }
+
+ if (parse_keyname((char*)cmd->data, cmd->len, namespace, keyname)) {
+ reply->retcode = -1;
+ } else {
+ reply->retcode = get_key(namespace, keyname, reply->data,
+ (int*)&reply->len);
+ }
+}
+
+static int get_value_index(LPC_MARSHAL *cmd)
+{
+ uint32_t count = 0, i;
+ for (i = 0 ; i < cmd->len ; ++i) {
+ if (cmd->data[i] == ' ') {
+ if (++count == 2) return ++i;
+ }
+ }
+ return -1;
+}
+
+// args of put():
+// namespace keyname keyvalue
+static void do_put_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ char namespace[MAX_KEY_NAME_LENGTH];
+ char keyname[MAX_KEY_NAME_LENGTH];
+
+ int p = get_value_index(cmd);
+ if (p == -1) {
+ reply->retcode = -1;
+ } else {
+ unsigned char *value;
+ if (parse_keyname((char*)cmd->data, p - 1, namespace, keyname)) {
+ reply->retcode = -1;
+ return;
+ }
+ value = &cmd->data[p];
+ int len = cmd->len - p;
+ reply->retcode = put_key(namespace, keyname, value, len);
+ }
+}
+
+// args of remove_key():
+// namespace keyname
+static void do_remove_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ char namespace[MAX_KEY_NAME_LENGTH];
+ char keyname[MAX_KEY_NAME_LENGTH];
+ if (parse_keyname((char*)cmd->data, cmd->len, namespace, keyname)) {
+ reply->retcode = -1;
+ return;
+ }
+ reply->retcode = remove_key(namespace, keyname);
+}
+
+// args of reset_keystore():
+// no argument
+static void do_reset_keystore(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ if (check_reset_perm(cr.uid)) {
+ LOGE("uid %d doesn't have the permission to reset the keystore\n",
+ cr.uid);
+ reply->retcode = -1;
+ return;
+ }
+ reply->retcode = reset_keystore();
+}
+
+static void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+{
+ uint32_t cmd_max = sizeof(cmds)/sizeof(struct cmdinfo);
+
+ if (cmd->opcode >= cmd_max) {
+ LOGE("the opcode (%d) is not valid", cmd->opcode);
+ reply->retcode = -1;
+ return;
+ }
+ cmds[cmd->opcode].func(cmd, reply);
+}
+
+static int set_read_timeout(int socket)
+{
+ struct timeval tv;
+ tv.tv_sec = READ_TIMEOUT;
+ if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
+ {
+ LOGE("setsockopt failed");
+ return -1;
+ }
+ return 0;
+}
+
+static int append_input_from_file(const char *filename, LPC_MARSHAL *cmd)
+{
+ int fd, len, ret = 0;
+
+ // get opcode of the function put()
+ if ((fd = open(filename, O_RDONLY)) == -1) {
+ fprintf(stderr, "Can not open file %s\n", filename);
+ return -1;
+ }
+ cmd->data[cmd->len] = ' ';
+ cmd->len++;
+ len = read(fd, cmd->data + cmd->len, BUFFER_MAX - cmd->len);
+ if (len < 0 || (len == (int)(BUFFER_MAX - cmd->len))) {
+ ret = -1;
+ } else {
+ cmd->len += len;
+ }
+ close(fd);
+ return ret;
+}
+
+static int flatten_str_args(int argc, const char **argv, LPC_MARSHAL *cmd)
+{
+ int i, len = 0;
+ char *buf = (char*)cmd->data;
+ buf[0] = 0;
+ for (i = 0 ; i < argc ; ++i) {
+ if (i == 0) {
+ len = strlcpy(buf, argv[i], BUFFER_MAX);
+ } else {
+ len += snprintf(buf + len, BUFFER_MAX - len, " %s", argv[i]);
+ }
+ if (len >= BUFFER_MAX) return -1;
+ }
+ if (len) cmd->len = len;
+ return 0;
+}
+
+static int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd)
+{
+ uint32_t i, len = 0;
+ uint32_t cmd_max = sizeof(cmds)/sizeof(cmds[0]);
+
+ for (i = 0 ; i < cmd_max ; ++i) {
+ if (!strcasecmp(argv[0], cmds[i].name)) break;
+ }
+
+ if (i == cmd_max) {
+ // check if this is a command to put the key value with a file.
+ if (strcmp(argv[0], CMD_PUT_WITH_FILE) != 0) return -1;
+ cmd->opcode = PUT;
+ if (argc != 4) {
+ fprintf(stderr, "%s args\n\tnamespace keyname filename\n",
+ argv[0]);
+ return -1;
+ }
+ if (flatten_str_args(argc - 2, argv + 1, cmd)) return -1;
+ return append_input_from_file(argv[3], cmd);
+ } else {
+ cmd->opcode = i;
+ return flatten_str_args(argc - 1, argv + 1, cmd);
+ }
+}
+
+static int shell_command(const int argc, const char **argv)
+{
+ int fd, i;
+ LPC_MARSHAL cmd;
+
+ if (parse_cmd(argc, argv , &cmd)) {
+ fprintf(stderr, "Incorrect command or command line is too long.\n");
+ exit(1);
+ }
+ fd = socket_local_client(SOCKET_PATH,
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (fd == -1) {
+ fprintf(stderr, "Keystore service is not up and running.\n");
+ exit(1);
+ }
+
+ if (write_marshal(fd, &cmd)) {
+ fprintf(stderr, "Incorrect command or command line is too long.\n");
+ exit(1);
+ }
+ if (read_marshal(fd, &cmd)) {
+ fprintf(stderr, "Failed to read the result.\n");
+ exit(1);
+ }
+ cmd.data[cmd.len] = 0;
+ fprintf(stdout, "%s\n", (cmd.retcode == 0) ? "Succeeded!" : "Failed!");
+ if (cmd.len) fprintf(stdout, "\t%s\n", (char*)cmd.data);
+ close(fd);
+ return 0;
+}
+
+int main(const int argc, const char *argv[])
+{
+ struct sockaddr addr;
+ socklen_t alen;
+ int lsocket, s;
+ LPC_MARSHAL cmd, reply;
+
+ if (argc > 1) {
+ return shell_command(argc - 1, argv + 1);
+ }
+
+ if (init_keystore(KEYSTORE_DIR)) {
+ LOGE("Can not initialize the keystore, the directory exist?\n");
+ exit(1);
+ }
+
+ lsocket = android_get_control_socket(SOCKET_PATH);
+ if (lsocket < 0) {
+ LOGE("Failed to get socket from environment: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (listen(lsocket, 5)) {
+ LOGE("Listen on socket failed: %s\n", strerror(errno));
+ exit(1);
+ }
+ fcntl(lsocket, F_SETFD, FD_CLOEXEC);
+ memset(&reply, 0, sizeof(LPC_MARSHAL));
+
+ for (;;) {
+ socklen_t cr_size = sizeof(cr);
+ alen = sizeof(addr);
+ s = accept(lsocket, &addr, &alen);
+
+ /* retrieve the caller info here */
+ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
+ close(s);
+ LOGE("Unable to recieve socket options\n");
+ continue;
+ }
+
+ if (s < 0) {
+ LOGE("Accept failed: %s\n", strerror(errno));
+ continue;
+ }
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (set_read_timeout(s)) {
+ close(s);
+ continue;
+ }
+
+ // read the command, execute and send the result back.
+ if(read_marshal(s, &cmd)) goto err;
+ LOGI("new connection\n");
+ execute(&cmd, &reply);
+ write_marshal(s, &reply);
+err:
+ memset(&reply, 0, sizeof(LPC_MARSHAL));
+ LOGI("closing connection\n");
+ close(s);
+ }
+
+ return 0;
+}
diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h
new file mode 100644
index 0000000..a87a667
--- /dev/null
+++ b/cmds/keystore/netkeystore.h
@@ -0,0 +1,96 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef __NETKEYSTORE_H__
+#define __NETKEYSTORE_H__
+
+#include <stdio.h>
+#include <cutils/sockets.h>
+#include <cutils/log.h>
+
+#include "common.h"
+
+static inline int readx(int s, void *_buf, int count)
+{
+ char *buf = _buf;
+ int n = 0, r;
+ if (count < 0) return -1;
+ while (n < count) {
+ r = read(s, buf + n, count - n);
+ if (r < 0) {
+ if (errno == EINTR) continue;
+ LOGE("read error: %s\n", strerror(errno));
+ return -1;
+ }
+ if (r == 0) {
+ LOGE("eof\n");
+ return -1; /* EOF */
+ }
+ n += r;
+ }
+ return 0;
+}
+
+static inline int writex(int s, const void *_buf, int count)
+{
+ const char *buf = _buf;
+ int n = 0, r;
+ if (count < 0) return -1;
+ while (n < count) {
+ r = write(s, buf + n, count - n);
+ if (r < 0) {
+ if (errno == EINTR) continue;
+ LOGE("write error: %s\n", strerror(errno));
+ return -1;
+ }
+ n += r;
+ }
+ return 0;
+}
+
+static inline int read_marshal(int s, LPC_MARSHAL *cmd)
+{
+ if (readx(s, cmd, 2 * sizeof(uint32_t))) {
+ LOGE("failed to read header\n");
+ return -1;
+ }
+ if (cmd->len > BUFFER_MAX) {
+ LOGE("invalid size %d\n", cmd->len);
+ return -1;
+ }
+ if (readx(s, cmd->data, cmd->len)) {
+ LOGE("failed to read data\n");
+ return -1;
+ }
+ cmd->data[cmd->len] = 0;
+ return 0;
+}
+
+static inline int write_marshal(int s, LPC_MARSHAL *cmd)
+{
+ if (writex(s, cmd, 2 * sizeof(uint32_t))) {
+ LOGE("failed to write marshal header\n");
+ return -1;
+ }
+ if (writex(s, cmd->data, cmd->len)) {
+ LOGE("failed to write marshal data\n");
+ return -1;
+ }
+ return 0;
+}
+
+#endif
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 1531a9e..476f38a 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -45,9 +45,9 @@
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
/* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST &
* CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE & CAP_KILL &
- * CAP_SYS_BOOT
+ * CAP_SYS_BOOT CAP_SYS_NICE
*/
- "--capabilities=88161312,88161312",
+ "--capabilities=96549920,96549920",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer"
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 0c7ad46..a85f275 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -456,7 +456,7 @@
void validate();
matrixf_t& top() { return stack[depth]; }
const matrixf_t& top() const { return stack[depth]; }
- const uint32_t top_ops() const { return ops[depth]; }
+ uint32_t top_ops() const { return ops[depth]; }
inline bool isRigidBody() const {
return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE));
}
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
new file mode 100644
index 0000000..21cb73b
--- /dev/null
+++ b/include/tts/TtsEngine.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <media/AudioSystem.h>
+
+// This header defines the interface used by the Android platform
+// to access Text-To-Speech functionality in shared libraries that implement
+// speech synthesis and the management of resources associated with the
+// synthesis.
+// An example of the implementation of this interface can be found in
+// FIXME: add path+name to implementation of default TTS engine
+// Libraries implementing this interface are used in:
+// frameworks/base/tts/jni/android_tts_SpeechSynthesis.cpp
+
+namespace android {
+
+enum tts_synth_status {
+ TTS_SYNTH_DONE = 0,
+ TTS_SYNTH_PENDING = 1
+};
+
+enum tts_callback_status {
+ TTS_CALLBACK_HALT = 0,
+ TTS_CALLBACK_CONTINUE = 1
+};
+
+// The callback is used by the implementation of this interface to notify its
+// client, the Android TTS service, that the last requested synthesis has been
+// completed. // TODO reword
+// The callback for synthesis completed takes:
+// @param [inout] void *& - The userdata pointer set in the original
+// synth call
+// @param [in] uint32_t - Track sampling rate in Hz
+// @param [in] audio_format - The AudioSystem::audio_format enum
+// @param [in] int - The number of channels
+// @param [inout] int8_t *& - A buffer of audio data only valid during the
+// execution of the callback
+// @param [inout] size_t & - The size of the buffer
+// @param [in] tts_synth_status - indicate whether the synthesis is done, or
+// if more data is to be synthesized.
+// @return TTS_CALLBACK_HALT to indicate the synthesis must stop,
+// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
+// there is more data to produce.
+typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
+ AudioSystem::audio_format, int, int8_t *&, size_t&, tts_synth_status);
+
+class TtsEngine;
+extern "C" TtsEngine* getTtsEngine();
+
+enum tts_result {
+ TTS_SUCCESS = 0,
+ TTS_FAILURE = -1,
+ TTS_FEATURE_UNSUPPORTED = -2,
+ TTS_VALUE_INVALID = -3,
+ TTS_PROPERTY_UNSUPPORTED = -4,
+ TTS_PROPERTY_SIZE_TOO_SMALL = -5,
+ TTS_MISSING_RESOURCES = -6
+};
+
+enum tts_support_result {
+ TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
+ TTS_LANG_COUNTRY_AVAILABLE = 1,
+ TTS_LANG_AVAILABLE = 0,
+ TTS_LANG_MISSING_DATA = -1,
+ TTS_LANG_NOT_SUPPORTED = -2
+};
+
+class TtsEngine
+{
+public:
+ // Initialize the TTS engine and returns whether initialization succeeded.
+ // @param synthDoneCBPtr synthesis callback function pointer
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result init(synthDoneCB_t synthDoneCBPtr);
+
+ // Shut down the TTS engine and releases all associated resources.
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result shutdown();
+
+ // Interrupt synthesis and flushes any synthesized data that hasn't been
+ // output yet. This will block until callbacks underway are completed.
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result stop();
+
+ // Returns the level of support for the language, country and variant.
+ // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
+ // and the corresponding resources are correctly installed
+ // TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
+ // corresponding resources are correctly installed, but there is no match for
+ // the specified variant
+ // TTS_LANG_AVAILABLE if the language is supported and the
+ // corresponding resources are correctly installed, but there is no match for
+ // the specified country and variant
+ // TTS_LANG_MISSING_DATA if the required resources to provide any level of support
+ // for the language are not correctly installed
+ // TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
+ virtual tts_support_result isLanguageAvailable(const char *lang, const char *country,
+ const char *variant);
+
+ // Load the resources associated with the specified language. The loaded
+ // language will only be used once a call to setLanguage() with the same
+ // language value is issued. Language and country values are coded according to the ISO three
+ // letter codes for languages and countries, as can be retrieved from a java.util.Locale
+ // instance. The variant value is encoded as the variant string retrieved from a
+ // java.util.Locale instance built with that variant data.
+ // @param lang pointer to the ISO three letter code for the language
+ // @param country pointer to the ISO three letter code for the country
+ // @param variant pointer to the variant code
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant);
+
+ // Load the resources associated with the specified language, country and Locale variant.
+ // The loaded language will only be used once a call to setLanguageFromLocale() with the same
+ // language value is issued. Language and country values are coded according to the ISO three
+ // letter codes for languages and countries, as can be retrieved from a java.util.Locale
+ // instance. The variant value is encoded as the variant string retrieved from a
+ // java.util.Locale instance built with that variant data.
+ // @param lang pointer to the ISO three letter code for the language
+ // @param country pointer to the ISO three letter code for the country
+ // @param variant pointer to the variant code
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
+
+ // Retrieve the currently set language, country and variant, or empty strings if none of
+ // parameters have been set. Language and country are represented by their 3-letter ISO code
+ // @param[out] pointer to the retrieved 3-letter code language value
+ // @param[out] pointer to the retrieved 3-letter code country value
+ // @param[out] pointer to the retrieved variant value
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result getLanguage(char *language, char *country, char *variant);
+
+ // Notifies the engine what audio parameters should be used for the synthesis.
+ // This is meant to be used as a hint, the engine implementation will set the output values
+ // to those of the synthesis format, based on a given hint.
+ // @param[inout] encoding in: the desired audio sample format
+ // out: the format used by the TTS engine
+ // @param[inout] rate in: the desired audio sample rate
+ // out: the sample rate used by the TTS engine
+ // @param[inout] channels in: the desired number of audio channels
+ // out: the number of channels used by the TTS engine
+ // @return TTS_SUCCESS, or TTS_FAILURE
+ virtual tts_result setAudioFormat(AudioSystem::audio_format& encoding, uint32_t& rate,
+ int& channels);
+
+ // Set a property for the the TTS engine
+ // "size" is the maximum size of "value" for properties "property"
+ // @param property pointer to the property name
+ // @param value pointer to the property value
+ // @param size maximum size required to store this type of property
+ // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
+ // or TTS_VALUE_INVALID
+ virtual tts_result setProperty(const char *property, const char *value,
+ const size_t size);
+
+ // Retrieve a property from the TTS engine
+ // @param property pointer to the property name
+ // @param[out] value pointer to the retrieved language value
+ // @param[inout] iosize in: stores the size available to store the
+ // property value.
+ // out: stores the size required to hold the language
+ // value if getLanguage() returned
+ // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise
+ // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS,
+ // or TTS_PROPERTY_SIZE_TOO_SMALL
+ virtual tts_result getProperty(const char *property, char *value,
+ size_t *iosize);
+
+ // Synthesize the text.
+ // As the synthesis is performed, the engine invokes the callback to notify
+ // the TTS framework that it has filled the given buffer, and indicates how
+ // many bytes it wrote. The callback is called repeatedly until the engine
+ // has generated all the audio data corresponding to the text.
+ // Note about the format of the input: the text parameter may use the
+ // following elements
+ // and their respective attributes as defined in the SSML 1.0 specification:
+ // * lang
+ // * say-as:
+ // o interpret-as
+ // * phoneme
+ // * voice:
+ // o gender,
+ // o age,
+ // o variant,
+ // o name
+ // * emphasis
+ // * break:
+ // o strength,
+ // o time
+ // * prosody:
+ // o pitch,
+ // o contour,
+ // o range,
+ // o rate,
+ // o duration,
+ // o volume
+ // * mark
+ // Differences between this text format and SSML are:
+ // * full SSML documents are not supported
+ // * namespaces are not supported
+ // Text is coded in UTF-8.
+ // @param text the UTF-8 text to synthesize
+ // @param userdata pointer to be returned when the call is invoked
+ // @param buffer the location where the synthesized data must be written
+ // @param bufferSize the number of bytes that can be written in buffer
+ // @return TTS_SUCCESS or TTS_FAILURE
+ virtual tts_result synthesizeText(const char *text, int8_t *buffer,
+ size_t bufferSize, void *userdata);
+
+ // Synthesize IPA text.
+ // As the synthesis is performed, the engine invokes the callback to notify
+ // the TTS framework that it has filled the given buffer, and indicates how
+ // many bytes it wrote. The callback is called repeatedly until the engine
+ // has generated all the audio data corresponding to the IPA data.
+ // @param ipa the IPA data to synthesize
+ // @param userdata pointer to be returned when the call is invoked
+ // @param buffer the location where the synthesized data must be written
+ // @param bufferSize the number of bytes that can be written in buffer
+ // @return TTS_FEATURE_UNSUPPORTED if IPA is not supported,
+ // otherwise TTS_SUCCESS or TTS_FAILURE
+ virtual tts_result synthesizeIpa(const char *ipa, int8_t *buffer,
+ size_t bufferSize, void *userdata);
+};
+
+} // namespace android
+
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 048bdd5..e3544ab 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -63,16 +63,12 @@
#define FRAME_CALLBACK_FLAG_CAMERA 0x05
#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER 0x07
-// msgType in notifyCallback function
+// msgType in notifyCallback and dataCallback functions
enum {
- CAMERA_MSG_ERROR,
+ CAMERA_MSG_ERROR = 0,
CAMERA_MSG_SHUTTER,
CAMERA_MSG_FOCUS,
- CAMERA_MSG_ZOOM
-};
-
-// msgType in dataCallback function
-enum {
+ CAMERA_MSG_ZOOM,
CAMERA_MSG_PREVIEW_FRAME,
CAMERA_MSG_VIDEO_FRAME,
CAMERA_MSG_POSTVIEW_FRAME,
@@ -80,16 +76,25 @@
CAMERA_MSG_COMPRESSED_IMAGE
};
+// camera fatal errors
+enum {
+ CAMERA_ERROR_UKNOWN = 1,
+ CAMERA_ERROR_SERVER_DIED = 100
+};
+
class ICameraService;
class ICamera;
class Surface;
class Mutex;
class String8;
-typedef void (*shutter_callback)(void *cookie);
-typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
-typedef void (*autofocus_callback)(bool focused, void *cookie);
-typedef void (*error_callback)(status_t err, void *cookie);
+// ref-counted object for callbacks
+class CameraListener: virtual public RefBase
+{
+public:
+ virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+ virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+};
class Camera : public BnCameraClient, public IBinder::DeathRecipient
{
@@ -144,13 +149,8 @@
// get preview/capture parameters - key/value pairs
String8 getParameters() const;
- void setShutterCallback(shutter_callback cb, void *cookie);
- void setRawCallback(frame_callback cb, void *cookie);
- void setJpegCallback(frame_callback cb, void *cookie);
- void setRecordingCallback(frame_callback cb, void *cookie);
- void setPreviewCallback(frame_callback cb, void *cookie, int preview_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
- void setErrorCallback(error_callback cb, void *cookie);
- void setAutoFocusCallback(autofocus_callback cb, void *cookie);
+ void setListener(const sp<CameraListener>& listener);
+ void setPreviewCallbackFlags(int preview_callback_flag);
// ICameraClient interface
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
@@ -160,6 +160,8 @@
private:
Camera();
+ Camera(const Camera&);
+ Camera& operator=(const Camera);
virtual void binderDied(const wp<IBinder>& who);
class DeathNotifier: public IBinder::DeathRecipient
@@ -179,20 +181,7 @@
sp<ICamera> mCamera;
status_t mStatus;
- shutter_callback mShutterCallback;
- void *mShutterCallbackCookie;
- frame_callback mRawCallback;
- void *mRawCallbackCookie;
- frame_callback mJpegCallback;
- void *mJpegCallbackCookie;
- frame_callback mPreviewCallback;
- void *mPreviewCallbackCookie;
- frame_callback mRecordingCallback;
- void *mRecordingCallbackCookie;
- error_callback mErrorCallback;
- void *mErrorCallbackCookie;
- autofocus_callback mAutoFocusCallback;
- void *mAutoFocusCallbackCookie;
+ sp<CameraListener> mListener;
friend class DeathNotifier;
diff --git a/include/ui/Point.h b/include/ui/Point.h
index dbbad1e..1653120 100644
--- a/include/ui/Point.h
+++ b/include/ui/Point.h
@@ -31,12 +31,9 @@
// because we want the compiler generated versions
// Default constructor doesn't initialize the Point
- inline Point()
- {
+ inline Point() {
}
-
- inline Point(int _x, int _y) : x(_x), y(_y)
- {
+ inline Point(int x, int y) : x(x), y(y) {
}
inline bool operator == (const Point& rhs) const {
@@ -57,8 +54,8 @@
}
inline Point& operator - () {
- x=-x;
- y=-y;
+ x = -x;
+ y = -y;
return *this;
}
@@ -73,11 +70,13 @@
return *this;
}
- Point operator + (const Point& rhs) const {
- return Point(x+rhs.x, y+rhs.y);
+ const Point operator + (const Point& rhs) const {
+ const Point result(x+rhs.x, y+rhs.y);
+ return result;
}
- Point operator - (const Point& rhs) const {
- return Point(x-rhs.x, y-rhs.y);
+ const Point operator - (const Point& rhs) const {
+ const Point result(x-rhs.x, y-rhs.y);
+ return result;
}
};
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index d232847..da72944 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -33,23 +33,16 @@
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
- inline Rect()
- {
+ inline Rect() {
}
-
inline Rect(int w, int h)
- : left(0), top(0), right(w), bottom(h)
- {
+ : left(0), top(0), right(w), bottom(h) {
}
-
inline Rect(int l, int t, int r, int b)
- : left(l), top(t), right(r), bottom(b)
- {
+ : left(l), top(t), right(r), bottom(b) {
}
-
inline Rect(const Point& lt, const Point& rb)
- : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y)
- {
+ : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) {
}
void makeInvalid();
@@ -78,21 +71,22 @@
return bottom-top;
}
- // returns left-top Point non-const reference, can be assigned
- inline Point& leftTop() {
- return reinterpret_cast<Point&>(left);
+ void setLeftTop(const Point& lt) {
+ left = lt.x;
+ top = lt.y;
}
- // returns right bottom non-const reference, can be assigned
- inline Point& rightBottom() {
- return reinterpret_cast<Point&>(right);
+
+ void setRightBottom(const Point& rb) {
+ right = rb.x;
+ bottom = rb.y;
}
// the following 4 functions return the 4 corners of the rect as Point
- inline const Point& leftTop() const {
- return reinterpret_cast<const Point&>(left);
+ Point leftTop() const {
+ return Point(left, top);
}
- inline const Point& rightBottom() const {
- return reinterpret_cast<const Point&>(right);
+ Point rightBottom() const {
+ return Point(right, bottom);
}
Point rightTop() const {
return Point(right, top);
@@ -133,8 +127,8 @@
Rect& operator -= (const Point& rhs) {
return offsetBy(-rhs.x, -rhs.y);
}
- Rect operator + (const Point& rhs) const;
- Rect operator - (const Point& rhs) const;
+ const Rect operator + (const Point& rhs) const;
+ const Rect operator - (const Point& rhs) const;
void translate(int dx, int dy) { // legacy, don't use.
offsetBy(dx, dy);
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index e94c0e8..d8994e0 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -153,6 +153,18 @@
AssetDir* openDir(const char* dirName);
/*
+ * Open a directory within a particular path of the asset manager.
+ *
+ * The contents of the directory are an amalgam of vendor-specific,
+ * locale-specific, and generic assets stored loosely or in asset
+ * packages. Depending on the cache setting and previous accesses,
+ * this call may incur significant disk overhead.
+ *
+ * To open the top-level directory, pass in "".
+ */
+ AssetDir* openNonAssetDir(void* cookie, const char* dirName);
+
+ /*
* Get the type of a file in the asset hierarchy. They will either
* be "regular" or "directory". [Currently only works for "regular".]
*
@@ -239,6 +251,9 @@
Asset* getResourceTableAsset();
Asset* setResourceTableAsset(Asset* asset);
+ ResTable* getResourceTable();
+ ResTable* setResourceTable(ResTable* res);
+
bool isUpToDate();
protected:
@@ -253,6 +268,7 @@
time_t mModWhen;
Asset* mResourceTableAsset;
+ ResTable* mResourceTable;
static Mutex gLock;
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
@@ -276,8 +292,11 @@
*/
ZipFileRO* getZip(const String8& path);
- Asset* getZipResourceTable(const String8& path);
- Asset* setZipResourceTable(const String8& path, Asset* asset);
+ Asset* getZipResourceTableAsset(const String8& path);
+ Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
+
+ ResTable* getZipResourceTable(const String8& path);
+ ResTable* setZipResourceTable(const String8& path, ResTable* res);
// generate path, e.g. "common/en-US-noogle.zip"
static String8 getPathName(const char* path);
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
new file mode 100644
index 0000000..b1f5045
--- /dev/null
+++ b/include/utils/BackupHelpers.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UTILS_BACKUP_HELPERS_H
+#define _UTILS_BACKUP_HELPERS_H
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+enum {
+ BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian)
+};
+
+typedef struct {
+ int type; // BACKUP_HEADER_ENTITY_V1
+ int keyLen; // length of the key name, not including the null terminator
+ int dataSize; // size of the data, not including the padding, -1 means delete
+} entity_header_v1;
+
+struct SnapshotHeader {
+ int magic0;
+ int fileCount;
+ int magic1;
+ int totalSize;
+};
+
+struct FileState {
+ int modTime_sec;
+ int modTime_nsec;
+ int mode;
+ int size;
+ int crc32;
+ int nameLen;
+};
+
+struct FileRec {
+ String8 file;
+ bool deleted;
+ FileState s;
+};
+
+
+/**
+ * Writes the data.
+ *
+ * If an error occurs, it poisons this object and all write calls will fail
+ * with the error that occurred.
+ */
+class BackupDataWriter
+{
+public:
+ BackupDataWriter(int fd);
+ // does not close fd
+ ~BackupDataWriter();
+
+ status_t WriteEntityHeader(const String8& key, size_t dataSize);
+ status_t WriteEntityData(const void* data, size_t size);
+
+ void SetKeyPrefix(const String8& keyPrefix);
+
+private:
+ explicit BackupDataWriter();
+ status_t write_padding_for(int n);
+
+ int m_fd;
+ status_t m_status;
+ ssize_t m_pos;
+ int m_entityCount;
+ String8 m_keyPrefix;
+};
+
+/**
+ * Reads the data.
+ *
+ * If an error occurs, it poisons this object and all write calls will fail
+ * with the error that occurred.
+ */
+class BackupDataReader
+{
+public:
+ BackupDataReader(int fd);
+ // does not close fd
+ ~BackupDataReader();
+
+ status_t Status();
+ status_t ReadNextHeader(bool* done, int* type);
+
+ bool HasEntities();
+ status_t ReadEntityHeader(String8* key, size_t* dataSize);
+ status_t SkipEntityData(); // must be called with the pointer at the begining of the data.
+ ssize_t ReadEntityData(void* data, size_t size);
+
+private:
+ explicit BackupDataReader();
+ status_t skip_padding();
+
+ int m_fd;
+ bool m_done;
+ status_t m_status;
+ ssize_t m_pos;
+ ssize_t m_dataEndPos;
+ int m_entityCount;
+ union {
+ int type;
+ entity_header_v1 entity;
+ } m_header;
+ String8 m_key;
+};
+
+int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
+ char const* const* files, char const* const *keys, int fileCount);
+
+class RestoreHelperBase
+{
+public:
+ RestoreHelperBase();
+ ~RestoreHelperBase();
+
+ status_t WriteFile(const String8& filename, BackupDataReader* in);
+ status_t WriteSnapshot(int fd);
+
+private:
+ void* m_buf;
+ bool m_loggedUnknownMetadata;
+ KeyedVector<String8,FileRec> m_files;
+};
+
+#define TEST_BACKUP_HELPERS 1
+
+#if TEST_BACKUP_HELPERS
+int backup_helper_test_empty();
+int backup_helper_test_four();
+int backup_helper_test_files();
+int backup_helper_test_null_base();
+int backup_helper_test_missing_file();
+int backup_helper_test_data_writer();
+int backup_helper_test_data_reader();
+#endif
+
+} // namespace android
+
+#endif // _UTILS_BACKUP_HELPERS_H
diff --git a/include/utils/ByteOrder.h b/include/utils/ByteOrder.h
index 4c06067..baa3a83 100644
--- a/include/utils/ByteOrder.h
+++ b/include/utils/ByteOrder.h
@@ -38,6 +38,16 @@
* intent is to allow us to avoid byte swapping on the device.
*/
+static inline uint32_t android_swap_long(uint32_t v)
+{
+ return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
+}
+
+static inline uint16_t android_swap_short(uint16_t v)
+{
+ return (v<<8) | (v>>8);
+}
+
#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
#if BYTE_ORDER == DEVICE_BYTE_ORDER
@@ -49,16 +59,6 @@
#else
-static inline uint32_t android_swap_long(uint32_t v)
-{
- return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
-}
-
-static inline uint16_t android_swap_short(uint16_t v)
-{
- return (v<<8) | (v>>8);
-}
-
#define dtohl(x) (android_swap_long(x))
#define dtohs(x) (android_swap_short(x))
#define htodl(x) (android_swap_long(x))
@@ -66,4 +66,16 @@
#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define fromlel(x) (x)
+#define fromles(x) (x)
+#define tolel(x) (x)
+#define toles(x) (x)
+#else
+#define fromlel(x) (android_swap_long(x))
+#define fromles(x) (android_swap_short(x))
+#define tolel(x) (android_swap_long(x))
+#define toles(x) (android_swap_short(x))
+#endif
+
#endif // _LIBS_UTILS_BYTE_ORDER_H
diff --git a/include/utils/Parcel.h b/include/utils/Parcel.h
index 9087c44..af1490a 100644
--- a/include/utils/Parcel.h
+++ b/include/utils/Parcel.h
@@ -80,8 +80,11 @@
status_t writeStrongBinder(const sp<IBinder>& val);
status_t writeWeakBinder(const wp<IBinder>& val);
- // doesn't take ownership of the native_handle
- status_t writeNativeHandle(const native_handle& handle);
+ // Place a native_handle into the parcel (the native_handle's file-
+ // descriptors are dup'ed, so it is safe to delete the native_handle
+ // when this function returns).
+ // Doesn't take ownership of the native_handle.
+ status_t writeNativeHandle(const native_handle* handle);
// Place a file descriptor into the parcel. The given fd must remain
// valid for the lifetime of the parcel.
@@ -114,12 +117,11 @@
wp<IBinder> readWeakBinder() const;
- // if alloc is NULL, native_handle is allocated with malloc(), otherwise
- // alloc is used. If the function fails, the effects of alloc() must be
- // reverted by the caller.
- native_handle* readNativeHandle(
- native_handle* (*alloc)(void* cookie, int numFds, int ints),
- void* cookie) const;
+ // Retrieve native_handle from the parcel. This returns a copy of the
+ // parcel's native_handle (the caller takes ownership). The caller
+ // must free the native_handle with native_handle_close() and
+ // native_handle_delete().
+ native_handle* readNativeHandle() const;
// Retrieve a file descriptor from the parcel. This returns the raw fd
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 9b8c302..93bca4a 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -71,7 +71,7 @@
* The relative sizes of the stretchy segments indicates the relative
* amount of stretchiness of the regions bordered by the segments. For
* example, regions 3, 7 and 11 above will take up more horizontal space
- * than regions 1, 5 and 9 since the horizonal segment associated with
+ * than regions 1, 5 and 9 since the horizontal segment associated with
* the first set of regions is larger than the other set of regions. The
* ratios of the amount of horizontal (or vertical) space taken by any
* two stretchable slices is exactly the ratio of their corresponding
@@ -87,7 +87,7 @@
* the leftmost slices always start at x=0 and the rightmost slices
* always end at the end of the image. So, for example, the regions 0,
* 4 and 8 (which are fixed along the X axis) start at x value 0 and
- * go to xDiv[0] amd slices 2, 6 and 10 start at xDiv[1] and end at
+ * go to xDiv[0] and slices 2, 6 and 10 start at xDiv[1] and end at
* xDiv[2].
*
* The array pointed to by the colors field lists contains hints for
@@ -626,25 +626,25 @@
event_code_t next();
// These are available for all nodes:
- const int32_t getCommentID() const;
+ int32_t getCommentID() const;
const uint16_t* getComment(size_t* outLen) const;
- const uint32_t getLineNumber() const;
+ uint32_t getLineNumber() const;
// This is available for TEXT:
- const int32_t getTextID() const;
+ int32_t getTextID() const;
const uint16_t* getText(size_t* outLen) const;
ssize_t getTextValue(Res_value* outValue) const;
// These are available for START_NAMESPACE and END_NAMESPACE:
- const int32_t getNamespacePrefixID() const;
+ int32_t getNamespacePrefixID() const;
const uint16_t* getNamespacePrefix(size_t* outLen) const;
- const int32_t getNamespaceUriID() const;
+ int32_t getNamespaceUriID() const;
const uint16_t* getNamespaceUri(size_t* outLen) const;
// These are available for START_TAG and END_TAG:
- const int32_t getElementNamespaceID() const;
+ int32_t getElementNamespaceID() const;
const uint16_t* getElementNamespace(size_t* outLen) const;
- const int32_t getElementNameID() const;
+ int32_t getElementNameID() const;
const uint16_t* getElementName(size_t* outLen) const;
// Remaining methods are for retrieving information about attributes
@@ -653,14 +653,14 @@
size_t getAttributeCount() const;
// Returns -1 if no namespace, -2 if idx out of range.
- const int32_t getAttributeNamespaceID(size_t idx) const;
+ int32_t getAttributeNamespaceID(size_t idx) const;
const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
- const int32_t getAttributeNameID(size_t idx) const;
+ int32_t getAttributeNameID(size_t idx) const;
const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
- const uint32_t getAttributeNameResID(size_t idx) const;
+ uint32_t getAttributeNameResID(size_t idx) const;
- const int32_t getAttributeValueStringID(size_t idx) const;
+ int32_t getAttributeValueStringID(size_t idx) const;
const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
int32_t getAttributeDataType(size_t idx) const;
@@ -866,7 +866,7 @@
uint8_t keyboard;
uint8_t navigation;
uint8_t inputFlags;
- uint8_t pad0;
+ uint8_t inputPad0;
};
uint32_t input;
};
@@ -905,6 +905,23 @@
uint32_t version;
};
+ enum {
+ SCREENLAYOUT_ANY = 0x0000,
+ SCREENLAYOUT_SMALL = 0x0001,
+ SCREENLAYOUT_NORMAL = 0x0002,
+ SCREENLAYOUT_LARGE = 0x0003,
+ };
+
+ union {
+ struct {
+ uint8_t screenLayout;
+ uint8_t screenConfigPad0;
+ uint8_t screenConfigPad1;
+ uint8_t screenConfigPad2;
+ };
+ uint32_t screenConfig;
+ };
+
inline void copyFromDeviceNoSwap(const ResTable_config& o) {
const size_t size = dtohl(o.size);
if (size >= sizeof(ResTable_config)) {
@@ -950,6 +967,8 @@
diff = (int32_t)(screenSize - o.screenSize);
if (diff != 0) return diff;
diff = (int32_t)(version - o.version);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenLayout - o.screenLayout);
return (int)diff;
}
@@ -967,7 +986,8 @@
CONFIG_ORIENTATION = 0x0080,
CONFIG_DENSITY = 0x0100,
CONFIG_SCREEN_SIZE = 0x0200,
- CONFIG_VERSION = 0x0400
+ CONFIG_VERSION = 0x0400,
+ CONFIG_SCREEN_LAYOUT = 0x0800
};
// Compare two configuration, returning CONFIG_* flags set for each value
@@ -985,6 +1005,7 @@
if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
if (version != o.version) diffs |= CONFIG_VERSION;
+ if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
return diffs;
}
@@ -1062,6 +1083,13 @@
}
}
+ if (screenConfig || o.screenConfig) {
+ if (screenLayout != o.screenLayout) {
+ if (!screenLayout) return false;
+ if (!o.screenLayout) return true;
+ }
+ }
+
if (version || o.version) {
if (sdkVersion != o.sdkVersion) {
if (!sdkVersion) return false;
@@ -1191,6 +1219,12 @@
}
}
+ if (screenConfig || o.screenConfig) {
+ if ((screenLayout != o.screenLayout) && requested->screenLayout) {
+ return (screenLayout);
+ }
+ }
+
if (version || o.version) {
if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
return (sdkVersion);
@@ -1282,6 +1316,12 @@
return false;
}
}
+ if (screenConfig != 0) {
+ if (settings.screenLayout != 0 && screenLayout != 0
+ && screenLayout != settings.screenLayout) {
+ return false;
+ }
+ }
if (version != 0) {
if (settings.sdkVersion != 0 && sdkVersion != 0
&& sdkVersion != settings.sdkVersion) {
@@ -1310,13 +1350,13 @@
String8 toString() const {
char buf[200];
- sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=0x%02x touch=0x%02x dens=0x%02x "
- "kbd=0x%02x nav=0x%02x input=0x%02x screenW=0x%04x screenH=0x%04x vers=%d.%d",
+ sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d "
+ "kbd=%d nav=%d input=%d scrnW=%d scrnH=%d layout=%d vers=%d.%d",
mcc, mnc,
language[0] ? language[0] : '-', language[1] ? language[1] : '-',
country[0] ? country[0] : '-', country[1] ? country[1] : '-',
orientation, touchscreen, density, keyboard, navigation, inputFlags,
- screenWidth, screenHeight, sdkVersion, minorVersion);
+ screenWidth, screenHeight, screenLayout, sdkVersion, minorVersion);
return String8(buf);
}
};
@@ -1401,7 +1441,7 @@
* This is the beginning of information about an entry in the resource
* table. It holds the reference to the name of this entry, and is
* immediately followed by one of:
- * * A Res_value structures, if FLAG_COMPLEX is -not- set.
+ * * A Res_value structure, if FLAG_COMPLEX is -not- set.
* * An array of ResTable_map structures, if FLAG_COMPLEX is set.
* These supply a set of name/value mappings of data.
*/
@@ -1540,6 +1580,7 @@
bool copyData=false);
status_t add(Asset* asset, void* cookie,
bool copyData=false);
+ status_t add(ResTable* src);
status_t getError() const;
@@ -1781,7 +1822,7 @@
void getLocales(Vector<String8>* locales) const;
#ifndef HAVE_ANDROID_OS
- void print() const;
+ void print(bool inclValues) const;
#endif
private:
@@ -1803,6 +1844,8 @@
status_t parsePackage(
const ResTable_package* const pkg, const Header* const header);
+ void print_value(const Package* pkg, const Res_value& value) const;
+
mutable Mutex mLock;
status_t mError;
diff --git a/include/utils/TimeUtils.h b/include/utils/TimeUtils.h
deleted file mode 100644
index b19e021..0000000
--- a/include/utils/TimeUtils.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_TIME_H
-#define ANDROID_TIME_H
-
-#include <time.h>
-#include <cutils/tztime.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-namespace android {
-
-/*
- * This class is the core implementation of the android.util.Time java
- * class. It doesn't implement some of the methods that are implemented
- * in Java. They could be done here, but it's not expected that this class
- * will be used. If that assumption is incorrect, feel free to update this
- * file. The reason to do it here is to not mix the implementation of this
- * class and the jni glue code.
- */
-class Time
-{
-public:
- struct tm t;
-
- // this object doesn't own this string
- const char *timezone;
-
- enum {
- SEC = 1,
- MIN = 2,
- HOUR = 3,
- MDAY = 4,
- MON = 5,
- YEAR = 6,
- WDAY = 7,
- YDAY = 8
- };
-
- static int compare(Time& a, Time& b);
-
- Time();
-
- void switchTimezone(const char *timezone);
- String8 format(const char *format, const struct strftime_locale *locale) const;
- void format2445(short* buf, bool hasTime) const;
- String8 toString() const;
- void setToNow();
- int64_t toMillis(bool ignoreDst);
- void set(int64_t millis);
-
- inline void set(int sec, int min, int hour, int mday, int mon, int year,
- int isdst)
- {
- this->t.tm_sec = sec;
- this->t.tm_min = min;
- this->t.tm_hour = hour;
- this->t.tm_mday = mday;
- this->t.tm_mon = mon;
- this->t.tm_year = year;
- this->t.tm_isdst = isdst;
-#ifdef HAVE_TM_GMTOFF
- this->t.tm_gmtoff = 0;
-#endif
- this->t.tm_wday = 0;
- this->t.tm_yday = 0;
- }
-};
-
-}; // namespace android
-
-#endif // ANDROID_TIME_H
diff --git a/include/utils/backup_helpers.h b/include/utils/backup_helpers.h
deleted file mode 100644
index 137c5f1..0000000
--- a/include/utils/backup_helpers.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _UTILS_BACKUP_HELPERS_H
-#define _UTILS_BACKUP_HELPERS_H
-
-int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
- char const* fileBase, char const* const* files, int fileCount);
-
-#define TEST_BACKUP_HELPERS 0
-
-#if TEST_BACKUP_HELPERS
-int backup_helper_test_empty();
-int backup_helper_test_four();
-int backup_helper_test_files();
-#endif
-
-#endif // _UTILS_BACKUP_HELPERS_H
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index b6d5078..16a4f2d 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -71,8 +71,8 @@
}
AudioStreamIn* A2dpAudioInterface::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status,
- AudioSystem::audio_in_acoustics acoustics)
+ int inputSource, int format, int channelCount, uint32_t sampleRate,
+ status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
if (status)
*status = -1;
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 7901a8c..091e775 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -55,6 +55,7 @@
status_t *status=0);
virtual AudioStreamIn* openInputStream(
+ int inputSource,
int format,
int channelCount,
uint32_t sampleRate,
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
index 1a467c7..81c5c39 100644
--- a/libs/audioflinger/AudioBufferProvider.h
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -36,6 +36,8 @@
};
size_t frameCount;
};
+
+ virtual ~AudioBufferProvider() {}
virtual status_t getNextBuffer(Buffer* buffer) = 0;
virtual void releaseBuffer(Buffer* buffer) = 0;
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 9a94102..b72c94e 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -78,9 +78,9 @@
virtual status_t setParameter(const char* key, const char* value)
{return mFinalInterface->setParameter(key, value);}
- virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status,
- AudioSystem::audio_in_acoustics acoustics)
- {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status, acoustics);}
+ virtual AudioStreamIn* openInputStream(int inputSource, int format, int channelCount,
+ uint32_t sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
+ { return mFinalInterface->openInputStream(inputSource, format, channelCount, sampleRate, status, acoustics); }
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index b56221f..8a19fbd 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -499,7 +499,8 @@
}
#ifdef WITH_A2DP
- LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
+ LOGV("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(),
+ IPCThreadState::self()->getCallingPid());
if (mode == AudioSystem::MODE_NORMAL &&
(mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
AutoMutex lock(&mLock);
@@ -817,19 +818,22 @@
{
AutoMutex lock(mHardwareLock);
if (mForcedSpeakerCount++ == 0) {
- mRouteRestoreTime = 0;
- mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
- if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
- usleep(mHardwareMixerThread->latency()*1000);
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareStatus = AUDIO_HW_IDLE;
- // delay track start so that audio hardware has time to siwtch routes
- usleep(kStartSleepTime);
+ if (mForcedRoute == 0) {
+ mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+ LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime);
+ if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+ LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+ mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+ usleep(mHardwareMixerThread->latency()*1000);
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ // delay track start so that audio hardware has time to siwtch routes
+ usleep(kStartSleepTime);
+ }
}
mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+ mRouteRestoreTime = 0;
}
LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
}
@@ -890,7 +894,7 @@
}
LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
} else {
- LOGE("mA2dpDisableCount is already zero");
+ LOGV("mA2dpDisableCount is already zero");
}
}
}
@@ -1277,7 +1281,7 @@
status_t lStatus;
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+ if (sampleRate > mSampleRate*2) {
LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
lStatus = BAD_VALUE;
goto Exit;
@@ -1553,7 +1557,6 @@
AudioFlinger::MixerThread::TrackBase::TrackBase(
const sp<MixerThread>& mixerThread,
const sp<Client>& client,
- int streamType,
uint32_t sampleRate,
int format,
int channelCount,
@@ -1563,7 +1566,6 @@
: RefBase(),
mMixerThread(mixerThread),
mClient(client),
- mStreamType(streamType),
mFrameCount(0),
mState(IDLE),
mClientTid(-1),
@@ -1594,8 +1596,8 @@
new(mCblk) audio_track_cblk_t();
// clear all buffers
mCblk->frameCount = frameCount;
- mCblk->sampleRate = (uint16_t)sampleRate;
- mCblk->channels = (uint16_t)channelCount;
+ mCblk->sampleRate = sampleRate;
+ mCblk->channels = (uint8_t)channelCount;
if (sharedBuffer == 0) {
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
@@ -1618,8 +1620,8 @@
new(mCblk) audio_track_cblk_t();
// clear all buffers
mCblk->frameCount = frameCount;
- mCblk->sampleRate = (uint16_t)sampleRate;
- mCblk->channels = (uint16_t)channelCount;
+ mCblk->sampleRate = sampleRate;
+ mCblk->channels = (uint8_t)channelCount;
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
// Force underrun condition to avoid false underrun callback until first data is
@@ -1680,7 +1682,7 @@
}
int AudioFlinger::MixerThread::TrackBase::channelCount() const {
- return mCblk->channels;
+ return (int)mCblk->channels;
}
void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
@@ -1713,12 +1715,13 @@
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
+ : TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
{
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
mMute = false;
mSharedBuffer = sharedBuffer;
+ mStreamType = streamType;
}
AudioFlinger::MixerThread::Track::~Track()
@@ -1902,15 +1905,15 @@
AudioFlinger::MixerThread::RecordTrack::RecordTrack(
const sp<MixerThread>& mixerThread,
const sp<Client>& client,
- int streamType,
+ int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags)
- : TrackBase(mixerThread, client, streamType, sampleRate, format,
+ : TrackBase(mixerThread, client, sampleRate, format,
channelCount, frameCount, flags, 0),
- mOverflow(false)
+ mOverflow(false), mInputSource(inputSource)
{
}
@@ -2235,7 +2238,7 @@
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
- int streamType,
+ int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
@@ -2258,18 +2261,12 @@
goto Exit;
}
- if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
+ if (uint32_t(inputSource) >= AudioRecord::NUM_INPUT_SOURCES) {
LOGE("invalid stream type");
lStatus = BAD_VALUE;
goto Exit;
}
- if (sampleRate > MAX_SAMPLE_RATE) {
- LOGE("Sample rate out of range");
- lStatus = BAD_VALUE;
- goto Exit;
- }
-
if (mAudioRecordThread == 0) {
LOGE("Audio record thread not started");
lStatus = NO_INIT;
@@ -2301,7 +2298,7 @@
frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
- recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+ recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, inputSource, sampleRate,
format, channelCount, frameCount, flags);
}
if (recordTrack->getCblk() == NULL) {
@@ -2407,7 +2404,9 @@
LOGV("AudioRecordThread: loop starting");
if (mRecordTrack != 0) {
- input = mAudioHardware->openInputStream(mRecordTrack->format(),
+ input = mAudioHardware->openInputStream(
+ mRecordTrack->inputSource(),
+ mRecordTrack->format(),
mRecordTrack->channelCount(),
mRecordTrack->sampleRate(),
&mStartStatus,
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index c7ca9ec..8e47b29 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -139,7 +139,7 @@
// record interface
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int streamType,
+ int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
@@ -232,7 +232,6 @@
TrackBase(const sp<MixerThread>& mixerThread,
const sp<Client>& client,
- int streamType,
uint32_t sampleRate,
int format,
int channelCount,
@@ -260,10 +259,6 @@
return mCblk;
}
- int type() const {
- return mStreamType;
- }
-
int format() const {
return mFormat;
}
@@ -293,7 +288,6 @@
sp<Client> mClient;
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk;
- int mStreamType;
void* mBuffer;
void* mBufferEnd;
uint32_t mFrameCount;
@@ -328,6 +322,11 @@
void mute(bool);
void setVolume(float left, float right);
+ int type() const {
+ return mStreamType;
+ }
+
+
protected:
friend class MixerThread;
friend class AudioFlinger;
@@ -364,6 +363,7 @@
int8_t mRetryCount;
sp<IMemory> mSharedBuffer;
bool mResetDone;
+ int mStreamType;
}; // end of Track
// record track
@@ -371,7 +371,7 @@
public:
RecordTrack(const sp<MixerThread>& mixerThread,
const sp<Client>& client,
- int streamType,
+ int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
@@ -385,6 +385,8 @@
bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+ int inputSource() const { return mInputSource; }
+
private:
friend class AudioFlinger;
friend class AudioFlinger::RecordHandle;
@@ -397,6 +399,7 @@
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
bool mOverflow;
+ int mInputSource;
};
// playback track
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index 62beada..1e159b8 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -30,6 +30,7 @@
#include <utils/String8.h>
#include "AudioHardwareGeneric.h"
+#include <media/AudioRecord.h>
namespace android {
@@ -93,9 +94,15 @@
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status,
- AudioSystem::audio_in_acoustics acoustics)
+ int inputSource, int format, int channelCount, uint32_t sampleRate,
+ status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
+ // check for valid input source
+ if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
+ (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ return 0;
+ }
+
AutoMutex lock(mLock);
// only one input stream allowed
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index c949aa1..c89df87 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -112,6 +112,7 @@
status_t *status=0);
virtual AudioStreamIn* openInputStream(
+ int inputSource,
int format,
int channelCount,
uint32_t sampleRate,
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index b13cb1c..0ab4c60 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -23,6 +23,7 @@
#include <utils/String8.h>
#include "AudioHardwareStub.h"
+#include <media/AudioRecord.h>
namespace android {
@@ -56,9 +57,15 @@
}
AudioStreamIn* AudioHardwareStub::openInputStream(
- int format, int channelCount, uint32_t sampleRate,
+ int inputSource, int format, int channelCount, uint32_t sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
+ // check for valid input source
+ if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
+ (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ return 0;
+ }
+
AudioStreamInStub* in = new AudioStreamInStub();
status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
if (status) {
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index d406424..bf63cc5 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -78,6 +78,7 @@
status_t *status=0);
virtual AudioStreamIn* openInputStream(
+ int inputSource,
int format,
int channelCount,
uint32_t sampleRate,
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 2212436..9272983 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -6,7 +6,6 @@
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
GPUHardware/GPUHardware.cpp \
- BootAnimation.cpp \
BlurFilter.cpp.arm \
CPUGauge.cpp \
Layer.cpp \
diff --git a/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
deleted file mode 100644
index db40385..0000000
--- a/libs/surfaceflinger/BootAnimation.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BootAnimation"
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <math.h>
-#include <fcntl.h>
-#include <utils/misc.h>
-
-#include <utils/threads.h>
-#include <utils/Atomic.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/AssetManager.h>
-
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/DisplayInfo.h>
-#include <ui/ISurfaceComposer.h>
-#include <ui/ISurfaceFlingerClient.h>
-#include <ui/EGLNativeWindowSurface.h>
-
-#include <core/SkBitmap.h>
-#include <images/SkImageDecoder.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <EGL/eglext.h>
-
-#include "BootAnimation.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
- Thread(false) {
- mSession = SurfaceComposerClient::clientForConnection(
- composer->createConnection()->asBinder());
-}
-
-BootAnimation::~BootAnimation() {
-}
-
-void BootAnimation::onFirstRef() {
- run("BootAnimation", PRIORITY_DISPLAY);
-}
-
-const sp<SurfaceComposerClient>& BootAnimation::session() const {
- return mSession;
-}
-
-status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
- const char* name) {
- Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
- if (!asset)
- return NO_INIT;
- SkBitmap bitmap;
- SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
- &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
- asset->close();
- delete asset;
-
- // ensure we can call getPixels(). No need to call unlock, since the
- // bitmap will go out of scope when we return from this method.
- bitmap.lockPixels();
-
- const int w = bitmap.width();
- const int h = bitmap.height();
- const void* p = bitmap.getPixels();
-
- GLint crop[4] = { 0, h, w, -h };
- texture->w = w;
- texture->h = h;
-
- glGenTextures(1, &texture->name);
- glBindTexture(GL_TEXTURE_2D, texture->name);
-
- switch (bitmap.getConfig()) {
- case SkBitmap::kA8_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
- GL_UNSIGNED_BYTE, p);
- break;
- case SkBitmap::kARGB_4444_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
- GL_UNSIGNED_SHORT_4_4_4_4, p);
- break;
- case SkBitmap::kARGB_8888_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
- GL_UNSIGNED_BYTE, p);
- break;
- case SkBitmap::kRGB_565_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, p);
- break;
- default:
- break;
- }
-
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- return NO_ERROR;
-}
-
-status_t BootAnimation::readyToRun() {
- mAssets.addDefaultAssets();
-
- DisplayInfo dinfo;
- status_t status = session()->getDisplayInfo(0, &dinfo);
- if (status)
- return -1;
-
- // create the native surface
- sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
- PIXEL_FORMAT_RGB_565);
- session()->openTransaction();
- s->setLayer(0x40000000);
- session()->closeTransaction();
-
- // initialize opengl and egl
- const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
- EGLint w, h, dummy;
- EGLint numConfigs;
- EGLConfig config;
- EGLSurface surface;
- EGLContext context;
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglChooseConfig(display, attribs, &config, 1, &numConfigs);
-
- mNativeWindowSurface = new EGLNativeWindowSurface(s);
- surface = eglCreateWindowSurface(display, config,
- mNativeWindowSurface.get(), NULL);
-
- context = eglCreateContext(display, config, NULL, NULL);
- eglQuerySurface(display, surface, EGL_WIDTH, &w);
- eglQuerySurface(display, surface, EGL_HEIGHT, &h);
- eglMakeCurrent(display, surface, surface, context);
- mDisplay = display;
- mContext = context;
- mSurface = surface;
- mWidth = w;
- mHeight = h;
- mFlingerSurface = s;
-
- // initialize GL
- glShadeModel(GL_FLAT);
- glEnable(GL_TEXTURE_2D);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
- return NO_ERROR;
-}
-
-void BootAnimation::requestExit() {
- mBarrier.open();
- Thread::requestExit();
-}
-
-bool BootAnimation::threadLoop() {
- bool r = android();
- eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroyContext(mDisplay, mContext);
- eglDestroySurface(mDisplay, mSurface);
- mNativeWindowSurface.clear();
- return r;
-}
-
-bool BootAnimation::android() {
- initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
- initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
-
- // clear screen
- glDisable(GL_DITHER);
- glDisable(GL_SCISSOR_TEST);
- glClear(GL_COLOR_BUFFER_BIT);
- eglSwapBuffers(mDisplay, mSurface);
-
- const GLint xc = (mWidth - mAndroid[0].w) / 2;
- const GLint yc = (mHeight - mAndroid[0].h) / 2;
- const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
-
- // draw and update only what we need
- mNativeWindowSurface->setSwapRectangle(updateRect.left,
- updateRect.top, updateRect.width(), updateRect.height());
-
- glEnable(GL_SCISSOR_TEST);
- glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
- updateRect.height());
-
- // Blend state
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
- const nsecs_t startTime = systemTime();
- do {
- nsecs_t now = systemTime();
- double time = now - startTime;
- float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
- GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
- GLint x = xc - offset;
-
- glDisable(GL_BLEND);
- glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
- glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
- glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
-
- glEnable(GL_BLEND);
- glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
- glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
-
- eglSwapBuffers(mDisplay, mSurface);
-
- // 12fps: don't animate too fast to preserve CPU
- const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
- if (sleepTime > 0)
- usleep(sleepTime);
- } while (!exitPending());
-
- glDeleteTextures(1, &mAndroid[0].name);
- glDeleteTextures(1, &mAndroid[1].name);
- return false;
-}
-
-// ---------------------------------------------------------------------------
-
-}
-; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
deleted file mode 100644
index 3fb6670..0000000
--- a/libs/surfaceflinger/BootAnimation.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_BOOTANIMATION_H
-#define ANDROID_BOOTANIMATION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/threads.h>
-#include <utils/AssetManager.h>
-
-#include <ui/ISurfaceComposer.h>
-#include <ui/SurfaceComposerClient.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-
-#include "Barrier.h"
-
-class SkBitmap;
-
-namespace android {
-
-class AssetManager;
-class EGLNativeWindowSurface;
-
-// ---------------------------------------------------------------------------
-
-class BootAnimation : public Thread
-{
-public:
- BootAnimation(const sp<ISurfaceComposer>& composer);
- virtual ~BootAnimation();
-
- const sp<SurfaceComposerClient>& session() const;
- virtual void requestExit();
-
-private:
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
-
- struct Texture {
- GLint w;
- GLint h;
- GLuint name;
- };
-
- status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
- bool android();
-
- sp<SurfaceComposerClient> mSession;
- AssetManager mAssets;
- Texture mAndroid[2];
- int mWidth;
- int mHeight;
- EGLDisplay mDisplay;
- EGLDisplay mContext;
- EGLDisplay mSurface;
- sp<Surface> mFlingerSurface;
- sp<EGLNativeWindowSurface> mNativeWindowSurface;
- Barrier mBarrier;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_BOOTANIMATION_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index f14d7e9..eec645e 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -189,9 +189,14 @@
char property[PROPERTY_VALUE_MAX];
- if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
- LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
- strcpy(property, "160");
+ /* Read density from build-specific ro.sf.lcd_density property
+ * except if it is overriden by qemu.sf.lcd_density.
+ */
+ if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
+ if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
+ LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
+ strcpy(property, "160");
+ }
}
mDensity = atoi(property) * (1.0f/160.0f);
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index e844350..397ddc8 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -114,7 +114,9 @@
}
if (mBitsMemory==0 || mSurface.data==0) {
- LOGE("not enough memory for layer bitmap size=%u", size);
+ LOGE("not enough memory for layer bitmap "
+ "size=%u (w=%d, h=%d, stride=%d, format=%d)",
+ size, int(w), int(h), int(stride), int(format));
allocator->dump("LayerBitmap");
mSurface.data = 0;
mSize = -1U;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 167a59b..ef4a8ea 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -61,6 +61,13 @@
#include "GPUHardware/GPUHardware.h"
+/* ideally AID_GRAPHICS would be in a semi-public header
+ * or there would be a way to map a user/group name to its id
+ */
+#ifndef AID_GRAPHICS
+#define AID_GRAPHICS 1003
+#endif
+
#define DISPLAY_COUNT 1
namespace android {
@@ -184,7 +191,6 @@
mDebugCpu(0),
mDebugFps(0),
mDebugBackground(0),
- mDebugNoBootAnimation(0),
mSyncObject(),
mDeplayedTransactionPending(0),
mConsoleSignals(0),
@@ -207,14 +213,11 @@
mDebugBackground = atoi(value);
property_get("debug.sf.showfps", value, "0");
mDebugFps = atoi(value);
- property_get("debug.sf.nobootanimation", value, "0");
- mDebugNoBootAnimation = atoi(value);
LOGI_IF(mDebugRegion, "showupdates enabled");
LOGI_IF(mDebugCpu, "showcpu enabled");
LOGI_IF(mDebugBackground, "showbackground enabled");
LOGI_IF(mDebugFps, "showfps enabled");
- LOGI_IF(mDebugNoBootAnimation, "boot animation disabled");
}
SurfaceFlinger::~SurfaceFlinger()
@@ -324,11 +327,8 @@
{
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
- LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
- if (mBootAnimation != 0) {
- mBootAnimation->requestExit();
- mBootAnimation.clear();
- }
+ LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ property_set("ctl.stop", "bootanim");
}
void SurfaceFlinger::onFirstRef()
@@ -456,10 +456,10 @@
if (mDebugCpu)
mCpuGauge = new CPUGauge(this, ms2ns(500));
- // the boot animation!
- if (mDebugNoBootAnimation == false)
- mBootAnimation = new BootAnimation(this);
-
+
+ // start boot animation
+ property_set("ctl.start", "bootanim");
+
return NO_ERROR;
}
@@ -771,10 +771,11 @@
dirty.orSelf(layer->visibleRegionScreen);
layer->contentDirty = false;
} else {
- // compute the exposed region
- // dirty = what's visible now - what's wasn't covered before
- // = what's visible now & what's was covered before
- dirty = visibleRegion.intersect(layer->coveredRegionScreen);
+ /* compute the exposed region:
+ * exposed = what's VISIBLE and NOT COVERED now
+ * but was COVERED before
+ */
+ dirty = (visibleRegion - coveredRegion) & layer->coveredRegionScreen;
}
dirty.subtractSelf(aboveOpaqueLayers);
@@ -783,7 +784,7 @@
// updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
- aboveCoveredLayers.orSelf(bounds);
+ aboveCoveredLayers.orSelf(visibleRegion);
// Store the visible region is screen space
layer->setVisibleRegion(visibleRegion);
@@ -1543,13 +1544,13 @@
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid)) {
+ if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.ACCESS_SURFACE_FLINGER")))
{
- const int uid = ipc->getCallingUid();
LOGE("Permission Denial: "
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index e023182..15913f2 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -36,7 +36,6 @@
#include <private/ui/SurfaceFlingerSynchro.h>
#include "Barrier.h"
-#include "BootAnimation.h"
#include "CPUGauge.h"
#include "Layer.h"
#include "Tokenizer.h"
@@ -347,7 +346,6 @@
sp<SurfaceHeapManager> mSurfaceHeapManager;
sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
- sp<BootAnimation> mBootAnimation;
nsecs_t mBootTime;
// Can only accessed from the main thread, these members
@@ -374,7 +372,6 @@
int mDebugCpu;
int mDebugFps;
int mDebugBackground;
- int mDebugNoBootAnimation;
// these are thread safe
mutable Barrier mReadyToRunBarrier;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 238c602..5f633bd 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -35,6 +35,8 @@
#include <utils/MemoryHeapPmem.h>
#include <utils/MemoryHeapBase.h>
+#include <EGL/eglnatives.h>
+
#include "GPUHardware/GPUHardware.h"
#include "SurfaceFlinger.h"
#include "VRamHeap.h"
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index f944357..7bbe38b 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -20,13 +20,11 @@
LayerState.cpp \
Overlay.cpp \
PixelFormat.cpp \
- Point.cpp \
Rect.cpp \
Region.cpp \
Surface.cpp \
SurfaceComposerClient.cpp \
- SurfaceFlingerSynchro.cpp \
- Time.cpp
+ SurfaceFlingerSynchro.cpp
LOCAL_SHARED_LIBRARIES := \
libcorecg \
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 6613700..975594f 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -85,20 +85,6 @@
void Camera::init()
{
mStatus = UNKNOWN_ERROR;
- mShutterCallback = 0;
- mShutterCallbackCookie = 0;
- mRawCallback = 0;
- mRawCallbackCookie = 0;
- mJpegCallback = 0;
- mJpegCallbackCookie = 0;
- mPreviewCallback = 0;
- mPreviewCallbackCookie = 0;
- mRecordingCallback = 0;
- mRecordingCallbackCookie = 0;
- mErrorCallback = 0;
- mErrorCallbackCookie = 0;
- mAutoFocusCallback = 0;
- mAutoFocusCallbackCookie = 0;
}
Camera::~Camera()
@@ -127,7 +113,6 @@
{
LOGV("disconnect");
if (mCamera != 0) {
- mErrorCallback = 0;
mCamera->disconnect();
mCamera = 0;
}
@@ -164,21 +149,21 @@
status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
{
LOGV("setPreviewDisplay");
- if (surface == 0) {
- LOGE("app passed NULL surface");
- return NO_INIT;
- }
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
- return c->setPreviewDisplay(surface->getISurface());
+ if (surface != 0) {
+ return c->setPreviewDisplay(surface->getISurface());
+ } else {
+ LOGD("app passed NULL surface");
+ return c->setPreviewDisplay(0);
+ }
}
status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
{
LOGV("setPreviewDisplay");
if (surface == 0) {
- LOGE("app passed NULL surface");
- return NO_INIT;
+ LOGD("app passed NULL surface");
}
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
@@ -186,7 +171,7 @@
}
-// start preview mode, must call setPreviewDisplay first
+// start preview mode
status_t Camera::startPreview()
{
LOGV("startPreview");
@@ -285,125 +270,49 @@
return params;
}
-void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
+void Camera::setListener(const sp<CameraListener>& listener)
{
- LOGV("setAutoFocusCallback");
- mAutoFocusCallback = cb;
- mAutoFocusCallbackCookie = cookie;
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
}
-void Camera::setShutterCallback(shutter_callback cb, void *cookie)
+void Camera::setPreviewCallbackFlags(int flag)
{
- LOGV("setShutterCallback");
- mShutterCallback = cb;
- mShutterCallbackCookie = cookie;
-}
-
-void Camera::setRawCallback(frame_callback cb, void *cookie)
-{
- LOGV("setRawCallback");
- mRawCallback = cb;
- mRawCallbackCookie = cookie;
-}
-
-void Camera::setJpegCallback(frame_callback cb, void *cookie)
-{
- LOGV("setJpegCallback");
- mJpegCallback = cb;
- mJpegCallbackCookie = cookie;
-}
-
-void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
-{
- LOGV("setPreviewCallback");
- mPreviewCallback = cb;
- mPreviewCallbackCookie = cookie;
+ LOGV("setPreviewCallbackFlags");
sp <ICamera> c = mCamera;
if (c == 0) return;
mCamera->setPreviewCallbackFlag(flag);
}
-void Camera::setRecordingCallback(frame_callback cb, void *cookie)
-{
- LOGV("setRecordingCallback");
- mRecordingCallback = cb;
- mRecordingCallbackCookie = cookie;
-}
-
-void Camera::setErrorCallback(error_callback cb, void *cookie)
-{
- LOGV("setErrorCallback");
- mErrorCallback = cb;
- mErrorCallbackCookie = cookie;
-}
-
// callback from camera service
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
- switch(msgType) {
- case CAMERA_MSG_ERROR:
- LOGV("errorCallback");
- if (mErrorCallback) {
- mErrorCallback((status_t)ext1, mErrorCallbackCookie);
- }
- break;
- case CAMERA_MSG_FOCUS:
- LOGV("autoFocusCallback");
- if (mAutoFocusCallback) {
- mAutoFocusCallback((bool)ext1, mAutoFocusCallbackCookie);
- }
- break;
- case CAMERA_MSG_SHUTTER:
- LOGV("shutterCallback");
- if (mShutterCallback) {
- mShutterCallback(mShutterCallbackCookie);
- }
- break;
- default:
- LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
- break;
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+ if (listener != NULL) {
+ listener->notify(msgType, ext1, ext2);
}
}
// callback from camera service when frame or image is ready
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
{
- switch(msgType) {
- case CAMERA_MSG_PREVIEW_FRAME:
- LOGV("previewCallback");
- if (mPreviewCallback) {
- mPreviewCallback(dataPtr, mPreviewCallbackCookie);
- }
- break;
- case CAMERA_MSG_VIDEO_FRAME:
- LOGV("recordingCallback");
- if (mRecordingCallback) {
- mRecordingCallback(dataPtr, mRecordingCallbackCookie);
- }
- break;
- case CAMERA_MSG_RAW_IMAGE:
- LOGV("rawCallback");
- if (mRawCallback) {
- mRawCallback(dataPtr, mRawCallbackCookie);
- }
- break;
- case CAMERA_MSG_COMPRESSED_IMAGE:
- LOGV("jpegCallback");
- if (mJpegCallback) {
- mJpegCallback(dataPtr, mJpegCallbackCookie);
- }
- break;
- default:
- LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
- break;
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+ if (listener != NULL) {
+ listener->postData(msgType, dataPtr);
}
}
void Camera::binderDied(const wp<IBinder>& who) {
LOGW("ICamera died");
- if (mErrorCallback) {
- mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
- }
+ notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0);
}
void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index dd6a798..dab5f71 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -35,6 +35,13 @@
// ---------------------------------------------------------------------------
+/* ideally AID_GRAPHICS would be in a semi-public header
+ * or there would be a way to map a user/group name to its id
+ */
+#ifndef AID_GRAPHICS
+#define AID_GRAPHICS 1003
+#endif
+
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
@@ -136,13 +143,13 @@
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
- const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid)) {
+ const int uid = ipc->getCallingUid();
+ const int self_pid = getpid();
+ if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.ACCESS_SURFACE_FLINGER")))
{
- const int uid = ipc->getCallingUid();
LOGE("Permission Denial: "
"can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
index b236edc..59c6514 100644
--- a/libs/ui/Overlay.cpp
+++ b/libs/ui/Overlay.cpp
@@ -129,12 +129,8 @@
OverlayRef::~OverlayRef()
{
if (mOwnHandle) {
- /* FIXME: handles should be promoted to "real" API and be handled by
- * the framework */
- for (int i=0 ; i<mOverlayHandle->numFds ; i++) {
- close(mOverlayHandle->data[i]);
- }
- free((void*)mOverlayHandle);
+ native_handle_close(mOverlayHandle);
+ native_handle_delete(const_cast<native_handle*>(mOverlayHandle));
}
}
@@ -147,7 +143,7 @@
uint32_t f = data.readInt32();
uint32_t ws = data.readInt32();
uint32_t hs = data.readInt32();
- native_handle* handle = data.readNativeHandle(NULL, NULL);
+ native_handle* handle = data.readNativeHandle();
result = new OverlayRef();
result->mOverlayHandle = handle;
@@ -169,7 +165,7 @@
reply->writeInt32(o->mFormat);
reply->writeInt32(o->mWidthStride);
reply->writeInt32(o->mHeightStride);
- reply->writeNativeHandle(*(o->mOverlayHandle));
+ reply->writeNativeHandle(o->mOverlayHandle);
} else {
reply->writeStrongBinder(NULL);
}
diff --git a/libs/ui/Point.cpp b/libs/ui/Point.cpp
deleted file mode 100644
index 438d49f..0000000
--- a/libs/ui/Point.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Point.cpp
- * Android
- *
- * Created on 11/16/2006.
- * Copyright 2005 The Android Open Source Project
- *
- */
-
-#include <ui/Point.h>
-
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 99e68bb..66b9576 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -1,21 +1,28 @@
/*
- * Rect.cpp
- * Android
+ * Copyright (C) 2009 The Android Open Source Project
*
- * Created on 10/14/05.
- * Copyright 2005 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include <ui/Rect.h>
namespace android {
-inline int min(int a, int b) {
+static inline int min(int a, int b) {
return (a<b) ? a : b;
}
-inline int max(int a, int b) {
+static inline int max(int a, int b) {
return (a>b) ? a : b;
}
@@ -64,14 +71,16 @@
return *this;
}
-Rect Rect::operator + (const Point& rhs) const
+const Rect Rect::operator + (const Point& rhs) const
{
- return Rect(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y);
+ const Rect result(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y);
+ return result;
}
-Rect Rect::operator - (const Point& rhs) const
+const Rect Rect::operator - (const Point& rhs) const
{
- return Rect(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y);
+ const Rect result(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y);
+ return result;
}
bool Rect::intersect(const Rect& with, Rect* result) const
diff --git a/libs/ui/Time.cpp b/libs/ui/Time.cpp
deleted file mode 100644
index b553913..0000000
--- a/libs/ui/Time.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#include <utils/TimeUtils.h>
-#include <stdio.h>
-#include <cutils/tztime.h>
-
-namespace android {
-
-static void
-dump(const Time& t)
-{
- #ifdef HAVE_TM_GMTOFF
- long tm_gmtoff = t.t.tm_gmtoff;
- #else
- long tm_gmtoff = 0;
- #endif
- printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n",
- t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday,
- t.t.tm_hour, t.t.tm_min, t.t.tm_sec,
- t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday);
-}
-
-Time::Time()
-{
- t.tm_sec = 0;
- t.tm_min = 0;
- t.tm_hour = 0;
- t.tm_mday = 0;
- t.tm_mon = 0;
- t.tm_year = 0;
- t.tm_wday = 0;
- t.tm_yday = 0;
- t.tm_isdst = -1; // we don't know, so let the C library determine
- #ifdef HAVE_TM_GMTOFF
- t.tm_gmtoff = 0;
- #endif
-}
-
-
-#define COMPARE_FIELD(field) do { \
- int diff = a.t.field - b.t.field; \
- if (diff != 0) return diff; \
- } while(0)
-
-int
-Time::compare(Time& a, Time& b)
-{
- if (0 == strcmp(a.timezone, b.timezone)) {
- // if the timezones are the same, we can easily compare the two
- // times. Otherwise, convert to milliseconds and compare that.
- // This requires that object be normalized.
- COMPARE_FIELD(tm_year);
- COMPARE_FIELD(tm_mon);
- COMPARE_FIELD(tm_mday);
- COMPARE_FIELD(tm_hour);
- COMPARE_FIELD(tm_min);
- COMPARE_FIELD(tm_sec);
- return 0;
- } else {
- int64_t am = a.toMillis(false /* use isDst */);
- int64_t bm = b.toMillis(false /* use isDst */);
- int64_t diff = am-bm;
- return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
- }
-}
-
-static const int DAYS_PER_MONTH[] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
-
-static inline int days_this_month(int year, int month)
-{
- int n = DAYS_PER_MONTH[month];
- if (n != 28) {
- return n;
- } else {
- int y = year;
- return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28;
- }
-}
-
-void
-Time::switchTimezone(const char* timezone)
-{
- time_t seconds = mktime_tz(&(this->t), this->timezone);
- localtime_tz(&seconds, &(this->t), timezone);
-}
-
-String8
-Time::format(const char *format, const struct strftime_locale *locale) const
-{
- char buf[257];
- int n = strftime_tz(buf, 257, format, &(this->t), locale);
- if (n > 0) {
- return String8(buf);
- } else {
- return String8();
- }
-}
-
-static inline short
-tochar(int n)
-{
- return (n >= 0 && n <= 9) ? ('0'+n) : ' ';
-}
-
-static inline short
-next_char(int *m, int k)
-{
- int n = *m / k;
- *m = *m % k;
- return tochar(n);
-}
-
-void
-Time::format2445(short* buf, bool hasTime) const
-{
- int n;
-
- n = t.tm_year+1900;
- buf[0] = next_char(&n, 1000);
- buf[1] = next_char(&n, 100);
- buf[2] = next_char(&n, 10);
- buf[3] = tochar(n);
-
- n = t.tm_mon+1;
- buf[4] = next_char(&n, 10);
- buf[5] = tochar(n);
-
- n = t.tm_mday;
- buf[6] = next_char(&n, 10);
- buf[7] = tochar(n);
-
- if (hasTime) {
- buf[8] = 'T';
-
- n = t.tm_hour;
- buf[9] = next_char(&n, 10);
- buf[10] = tochar(n);
-
- n = t.tm_min;
- buf[11] = next_char(&n, 10);
- buf[12] = tochar(n);
-
- n = t.tm_sec;
- buf[13] = next_char(&n, 10);
- buf[14] = tochar(n);
- bool inUtc = strcmp("UTC", timezone) == 0;
- if (inUtc) {
- buf[15] = 'Z';
- }
- }
-}
-
-String8
-Time::toString() const
-{
- String8 str;
- char* s = str.lockBuffer(150);
- #ifdef HAVE_TM_GMTOFF
- long tm_gmtoff = t.tm_gmtoff;
- #else
- long tm_gmtoff = 0;
- #endif
- sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)",
- t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min,
- t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst,
- (int)(((Time*)this)->toMillis(false /* use isDst */)/1000));
- str.unlockBuffer();
- return str;
-}
-
-void
-Time::setToNow()
-{
- time_t seconds;
- time(&seconds);
- localtime_tz(&seconds, &(this->t), this->timezone);
-}
-
-int64_t
-Time::toMillis(bool ignoreDst)
-{
- if (ignoreDst) {
- this->t.tm_isdst = -1;
- }
- int64_t r = mktime_tz(&(this->t), this->timezone);
- if (r == -1)
- return -1;
- return r * 1000;
-}
-
-void
-Time::set(int64_t millis)
-{
- time_t seconds = millis / 1000;
- localtime_tz(&seconds, &(this->t), this->timezone);
-}
-
-}; // namespace android
-
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index f9fb780..9bdd64a 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -117,7 +117,8 @@
IPermissionController.cpp \
IServiceManager.cpp \
Unicode.cpp \
- file_backup_helper.cpp
+ BackupData.cpp \
+ BackupHelpers.cpp
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_SRC_FILES += $(hostSources)
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
index 91203dd..23cb72d 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/utils/Asset.cpp
@@ -582,11 +582,14 @@
if ((((size_t)data)&0x3) == 0) {
// We can return this directly if it is aligned on a word
// boundary.
+ LOGV("Returning aligned FileAsset %p (%s).", this,
+ getAssetSource());
return data;
}
// If not aligned on a word boundary, then we need to copy it into
// our own buffer.
- LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength);
+ LOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
+ getAssetSource(), (int)mLength);
unsigned char* buf = new unsigned char[mLength];
if (buf == NULL) {
LOGE("alloc of %ld bytes failed\n", (long) mLength);
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 447b801..5a05e6a 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -395,21 +395,41 @@
const size_t N = mAssetPaths.size();
for (size_t i=0; i<N; i++) {
Asset* ass = NULL;
+ ResTable* sharedRes = NULL;
bool shared = true;
const asset_path& ap = mAssetPaths.itemAt(i);
LOGV("Looking for resource asset in '%s'\n", ap.path.string());
if (ap.type != kFileTypeDirectory) {
- ass = const_cast<AssetManager*>(this)->
- mZipSet.getZipResourceTable(ap.path);
- if (ass == NULL) {
- LOGV("loading resource table %s\n", ap.path.string());
+ if (i == 0) {
+ // The first item is typically the framework resources,
+ // which we want to avoid parsing every time.
+ sharedRes = const_cast<AssetManager*>(this)->
+ mZipSet.getZipResourceTable(ap.path);
+ }
+ if (sharedRes == NULL) {
ass = const_cast<AssetManager*>(this)->
- openNonAssetInPathLocked("resources.arsc",
- Asset::ACCESS_BUFFER,
- ap);
- if (ass != NULL && ass != kExcludedAsset) {
+ mZipSet.getZipResourceTableAsset(ap.path);
+ if (ass == NULL) {
+ LOGV("loading resource table %s\n", ap.path.string());
ass = const_cast<AssetManager*>(this)->
- mZipSet.setZipResourceTable(ap.path, ass);
+ openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER,
+ ap);
+ if (ass != NULL && ass != kExcludedAsset) {
+ ass = const_cast<AssetManager*>(this)->
+ mZipSet.setZipResourceTableAsset(ap.path, ass);
+ }
+ }
+
+ if (i == 0 && ass != NULL) {
+ // If this is the first resource table in the asset
+ // manager, then we are going to cache it so that we
+ // can quickly copy it out for others.
+ LOGV("Creating shared resources for %s", ap.path.string());
+ sharedRes = new ResTable();
+ sharedRes->add(ass, (void*)(i+1), false);
+ sharedRes = const_cast<AssetManager*>(this)->
+ mZipSet.setZipResourceTable(ap.path, sharedRes);
}
}
} else {
@@ -420,13 +440,19 @@
ap);
shared = false;
}
- if (ass != NULL && ass != kExcludedAsset) {
+ if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
if (rt == NULL) {
mResources = rt = new ResTable();
updateResourceParamsLocked();
}
LOGV("Installing resource asset %p in to table %p\n", ass, mResources);
- rt->add(ass, (void*)(i+1), !shared);
+ if (sharedRes != NULL) {
+ LOGV("Copying existing resources for %s", ap.path.string());
+ rt->add(sharedRes);
+ } else {
+ LOGV("Parsing resources for %s", ap.path.string());
+ rt->add(ass, (void*)(i+1), !shared);
+ }
if (!shared) {
delete ass;
@@ -901,6 +927,60 @@
}
/*
+ * Open a directory in the non-asset namespace.
+ *
+ * An "asset directory" is simply the combination of all files in all
+ * locations, with ".gz" stripped for loose files. With app, locale, and
+ * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ *
+ * Pass in "" for the root dir.
+ */
+AssetDir* AssetManager::openNonAssetDir(void* cookie, const char* dirName)
+{
+ AutoMutex _l(mLock);
+
+ AssetDir* pDir = NULL;
+ SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
+
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+ assert(dirName != NULL);
+
+ //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
+
+ if (mCacheMode != CACHE_OFF && !mCacheValid)
+ loadFileNameCacheLocked();
+
+ pDir = new AssetDir;
+
+ pMergedInfo = new SortedVector<AssetDir::FileInfo>;
+
+ const size_t which = ((size_t)cookie)-1;
+
+ if (which < mAssetPaths.size()) {
+ const asset_path& ap = mAssetPaths.itemAt(which);
+ if (ap.type == kFileTypeRegular) {
+ LOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+ scanAndMergeZipLocked(pMergedInfo, ap, NULL, dirName);
+ } else {
+ LOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+ scanAndMergeDirLocked(pMergedInfo, ap, NULL, dirName);
+ }
+ }
+
+#if 0
+ printf("FILE LIST:\n");
+ for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
+ printf(" %d: (%d) '%s'\n", i,
+ pMergedInfo->itemAt(i).getFileType(),
+ (const char*) pMergedInfo->itemAt(i).getFileName());
+ }
+#endif
+
+ pDir->setFileList(pMergedInfo);
+ return pDir;
+}
+
+/*
* Scan the contents of the specified directory and merge them into the
* "pMergedInfo" vector, removing previous entries if we find "exclude"
* directives.
@@ -1143,6 +1223,7 @@
LOGE("ARGH: name too long?\n");
continue;
}
+ //printf("Comparing %s in %s?\n", nameBuf, dirName.string());
if (dirNameLen == 0 ||
(strncmp(nameBuf, dirName.string(), dirNameLen) == 0 &&
nameBuf[dirNameLen] == '/'))
@@ -1165,7 +1246,7 @@
createZipSourceNameLocked(zipName, dirName, info.getFileName()));
contents.add(info);
- //printf("FOUND: file '%s'\n", (const char*) info.mFileName);
+ //printf("FOUND: file '%s'\n", info.getFileName().string());
} else {
/* this is a subdir; add it if we don't already have it*/
String8 subdirName(cp, nextSlash - cp);
@@ -1181,7 +1262,7 @@
dirs.add(subdirName);
}
- //printf("FOUND: dir '%s'\n", (const char*) subdirName);
+ //printf("FOUND: dir '%s'\n", subdirName.string());
}
}
}
@@ -1455,7 +1536,8 @@
DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
- : mPath(path), mZipFile(NULL), mModWhen(modWhen), mResourceTableAsset(NULL)
+ : mPath(path), mZipFile(NULL), mModWhen(modWhen),
+ mResourceTableAsset(NULL), mResourceTable(NULL)
{
//LOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
mZipFile = new ZipFileRO;
@@ -1508,6 +1590,25 @@
return mResourceTableAsset;
}
+ResTable* AssetManager::SharedZip::getResourceTable()
+{
+ LOGV("Getting from SharedZip %p resource table %p\n", this, mResourceTable);
+ return mResourceTable;
+}
+
+ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res)
+{
+ {
+ AutoMutex _l(gLock);
+ if (mResourceTable == NULL) {
+ mResourceTable = res;
+ return res;
+ }
+ }
+ delete res;
+ return mResourceTable;
+}
+
bool AssetManager::SharedZip::isUpToDate()
{
time_t modWhen = getFileModDate(mPath.string());
@@ -1517,6 +1618,9 @@
AssetManager::SharedZip::~SharedZip()
{
//LOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
+ if (mResourceTable != NULL) {
+ delete mResourceTable;
+ }
if (mResourceTableAsset != NULL) {
delete mResourceTableAsset;
}
@@ -1572,7 +1676,7 @@
return zip->getZip();
}
-Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path)
+Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
{
int idx = getIndex(path);
sp<SharedZip> zip = mZipFile[idx];
@@ -1583,7 +1687,7 @@
return zip->getResourceTableAsset();
}
-Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path,
+Asset* AssetManager::ZipSet::setZipResourceTableAsset(const String8& path,
Asset* asset)
{
int idx = getIndex(path);
@@ -1592,6 +1696,26 @@
return zip->setResourceTableAsset(asset);
}
+ResTable* AssetManager::ZipSet::getZipResourceTable(const String8& path)
+{
+ int idx = getIndex(path);
+ sp<SharedZip> zip = mZipFile[idx];
+ if (zip == NULL) {
+ zip = SharedZip::get(path);
+ mZipFile.editItemAt(idx) = zip;
+ }
+ return zip->getResourceTable();
+}
+
+ResTable* AssetManager::ZipSet::setZipResourceTable(const String8& path,
+ ResTable* res)
+{
+ int idx = getIndex(path);
+ sp<SharedZip> zip = mZipFile[idx];
+ // doesn't make sense to call before previously accessing.
+ return zip->setResourceTable(res);
+}
+
/*
* Generate the partial pathname for the specified archive. The caller
* gets to prepend the asset root directory.
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
new file mode 100644
index 0000000..cce754a
--- /dev/null
+++ b/libs/utils/BackupData.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "backup_data"
+
+#include <utils/BackupHelpers.h>
+#include <utils/ByteOrder.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+
+namespace android {
+
+/*
+ * File Format (v1):
+ *
+ * All ints are stored little-endian.
+ *
+ * - An app_header_v1 struct.
+ * - The name of the package, utf-8, null terminated, padded to 4-byte boundary.
+ * - A sequence of zero or more key/value paires (entities), each with
+ * - A entity_header_v1 struct
+ * - The key, utf-8, null terminated, padded to 4-byte boundary.
+ * - The value, padded to 4 byte boundary
+ */
+
+const static int ROUND_UP[4] = { 0, 3, 2, 1 };
+
+static inline size_t
+round_up(size_t n)
+{
+ return n + ROUND_UP[n % 4];
+}
+
+static inline size_t
+padding_extra(size_t n)
+{
+ return ROUND_UP[n % 4];
+}
+
+BackupDataWriter::BackupDataWriter(int fd)
+ :m_fd(fd),
+ m_status(NO_ERROR),
+ m_pos(0),
+ m_entityCount(0)
+{
+}
+
+BackupDataWriter::~BackupDataWriter()
+{
+}
+
+// Pad out anything they've previously written to the next 4 byte boundary.
+status_t
+BackupDataWriter::write_padding_for(int n)
+{
+ ssize_t amt;
+ ssize_t paddingSize;
+
+ paddingSize = padding_extra(n);
+ if (paddingSize > 0) {
+ uint32_t padding = 0xbcbcbcbc;
+ amt = write(m_fd, &padding, paddingSize);
+ if (amt != paddingSize) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+ }
+ return NO_ERROR;
+}
+
+status_t
+BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ ssize_t amt;
+
+ amt = write_padding_for(m_pos);
+ if (amt != 0) {
+ return amt;
+ }
+
+ String8 k;
+ if (m_keyPrefix.length() > 0) {
+ k = m_keyPrefix;
+ k += ":";
+ k += key;
+ } else {
+ k = key;
+ }
+ if (true) {
+ LOGD("Writing entity: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), key.string(),
+ dataSize);
+ }
+
+ entity_header_v1 header;
+ ssize_t keyLen;
+
+ keyLen = k.length();
+
+ header.type = tolel(BACKUP_HEADER_ENTITY_V1);
+ header.keyLen = tolel(keyLen);
+ header.dataSize = tolel(dataSize);
+
+ amt = write(m_fd, &header, sizeof(entity_header_v1));
+ if (amt != sizeof(entity_header_v1)) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ amt = write(m_fd, k.string(), keyLen+1);
+ if (amt != keyLen+1) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ amt = write_padding_for(keyLen+1);
+
+ m_entityCount++;
+
+ return amt;
+}
+
+status_t
+BackupDataWriter::WriteEntityData(const void* data, size_t size)
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ // We don't write padding here, because they're allowed to call this several
+ // times with smaller buffers. We write it at the end of WriteEntityHeader
+ // instead.
+ ssize_t amt = write(m_fd, data, size);
+ if (amt != (ssize_t)size) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+ return NO_ERROR;
+}
+
+void
+BackupDataWriter::SetKeyPrefix(const String8& keyPrefix)
+{
+ m_keyPrefix = keyPrefix;
+}
+
+
+BackupDataReader::BackupDataReader(int fd)
+ :m_fd(fd),
+ m_done(false),
+ m_status(NO_ERROR),
+ m_pos(0),
+ m_entityCount(0)
+{
+ memset(&m_header, 0, sizeof(m_header));
+}
+
+BackupDataReader::~BackupDataReader()
+{
+}
+
+status_t
+BackupDataReader::Status()
+{
+ return m_status;
+}
+
+#define CHECK_SIZE(actual, expected) \
+ do { \
+ if ((actual) != (expected)) { \
+ if ((actual) == 0) { \
+ m_status = EIO; \
+ } else { \
+ m_status = errno; \
+ } \
+ return m_status; \
+ } \
+ } while(0)
+#define SKIP_PADDING() \
+ do { \
+ status_t err = skip_padding(); \
+ if (err != NO_ERROR) { \
+ m_status = err; \
+ return err; \
+ } \
+ } while(0)
+
+status_t
+BackupDataReader::ReadNextHeader(bool* done, int* type)
+{
+ *done = m_done;
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ int amt;
+
+ // No error checking here, in case we're at the end of the stream. Just let read() fail.
+ skip_padding();
+ amt = read(m_fd, &m_header, sizeof(m_header));
+ *done = m_done = (amt == 0);
+ CHECK_SIZE(amt, sizeof(m_header));
+ m_pos += sizeof(m_header);
+ if (type) {
+ *type = m_header.type;
+ }
+
+ // validate and fix up the fields.
+ m_header.type = fromlel(m_header.type);
+ switch (m_header.type)
+ {
+ case BACKUP_HEADER_ENTITY_V1:
+ {
+ m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
+ if (m_header.entity.keyLen <= 0) {
+ LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos,
+ (int)m_header.entity.keyLen);
+ m_status = EINVAL;
+ }
+ m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
+ m_entityCount++;
+
+ // read the rest of the header (filename)
+ size_t size = m_header.entity.keyLen;
+ char* buf = m_key.lockBuffer(size);
+ if (buf == NULL) {
+ m_status = ENOMEM;
+ return m_status;
+ }
+ int amt = read(m_fd, buf, size+1);
+ CHECK_SIZE(amt, (int)size+1);
+ m_key.unlockBuffer(size);
+ m_pos += size+1;
+ SKIP_PADDING();
+ m_dataEndPos = m_pos + m_header.entity.dataSize;
+
+ break;
+ }
+ default:
+ LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
+ m_status = EINVAL;
+ }
+
+ return m_status;
+}
+
+bool
+BackupDataReader::HasEntities()
+{
+ return m_status == NO_ERROR && m_header.type == BACKUP_HEADER_ENTITY_V1;
+}
+
+status_t
+BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize)
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+ if (m_header.type != BACKUP_HEADER_ENTITY_V1) {
+ return EINVAL;
+ }
+ *key = m_key;
+ *dataSize = m_header.entity.dataSize;
+ return NO_ERROR;
+}
+
+status_t
+BackupDataReader::SkipEntityData()
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+ if (m_header.type != BACKUP_HEADER_ENTITY_V1) {
+ return EINVAL;
+ }
+ if (m_header.entity.dataSize > 0) {
+ int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
+ return pos == -1 ? (int)errno : (int)NO_ERROR;
+ } else {
+ return NO_ERROR;
+ }
+}
+
+ssize_t
+BackupDataReader::ReadEntityData(void* data, size_t size)
+{
+ if (m_status != NO_ERROR) {
+ return -1;
+ }
+ int remaining = m_dataEndPos - m_pos;
+ //LOGD("ReadEntityData size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
+ // size, m_pos, m_dataEndPos, remaining);
+ if (remaining <= 0) {
+ return 0;
+ }
+ if (((int)size) > remaining) {
+ size = remaining;
+ }
+ //LOGD(" reading %d bytes", size);
+ int amt = read(m_fd, data, size);
+ if (amt < 0) {
+ m_status = errno;
+ return -1;
+ }
+ m_pos += amt;
+ return amt;
+}
+
+status_t
+BackupDataReader::skip_padding()
+{
+ ssize_t amt;
+ ssize_t paddingSize;
+
+ paddingSize = padding_extra(m_pos);
+ if (paddingSize > 0) {
+ uint32_t padding;
+ amt = read(m_fd, &padding, paddingSize);
+ CHECK_SIZE(amt, paddingSize);
+ m_pos += amt;
+ }
+ return NO_ERROR;
+}
+
+
+} // namespace android
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
new file mode 100644
index 0000000..4ad9b51
--- /dev/null
+++ b/libs/utils/BackupHelpers.cpp
@@ -0,0 +1,1314 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "file_backup_helper"
+
+#include <utils/BackupHelpers.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/ByteOrder.h>
+#include <utils/String8.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/time.h> // for utimes
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <zlib.h>
+
+#include <cutils/log.h>
+
+namespace android {
+
+#define MAGIC0 0x70616e53 // Snap
+#define MAGIC1 0x656c6946 // File
+
+/*
+ * File entity data format (v1):
+ *
+ * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
+ * - 12 bytes of metadata
+ * - the file data itself
+ *
+ * i.e. a 16-byte metadata header followed by the raw file data. If the
+ * restore code does not recognize the metadata version, it can still
+ * interpret the file data itself correctly.
+ *
+ * file_metadata_v1:
+ *
+ * - 4 byte version number === 0x00000001 (little endian)
+ * - 4-byte access mode (little-endian)
+ * - undefined (8 bytes)
+ */
+
+struct file_metadata_v1 {
+ int version;
+ int mode;
+ int undefined_1;
+ int undefined_2;
+};
+
+const static int CURRENT_METADATA_VERSION = 1;
+
+#if 1
+#define LOGP(f, x...)
+#else
+#if TEST_BACKUP_HELPERS
+#define LOGP(f, x...) printf(f "\n", x)
+#else
+#define LOGP(x...) LOGD(x)
+#endif
+#endif
+
+const static int ROUND_UP[4] = { 0, 3, 2, 1 };
+
+static inline int
+round_up(int n)
+{
+ return n + ROUND_UP[n % 4];
+}
+
+static int
+read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
+{
+ int bytesRead = 0;
+ int amt;
+ SnapshotHeader header;
+
+ amt = read(fd, &header, sizeof(header));
+ if (amt != sizeof(header)) {
+ return errno;
+ }
+ bytesRead += amt;
+
+ if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
+ LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
+ return 1;
+ }
+
+ for (int i=0; i<header.fileCount; i++) {
+ FileState file;
+ char filenameBuf[128];
+
+ amt = read(fd, &file, sizeof(FileState));
+ if (amt != sizeof(FileState)) {
+ LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
+ return 1;
+ }
+ bytesRead += amt;
+
+ // filename is not NULL terminated, but it is padded
+ int nameBufSize = round_up(file.nameLen);
+ char* filename = nameBufSize <= (int)sizeof(filenameBuf)
+ ? filenameBuf
+ : (char*)malloc(nameBufSize);
+ amt = read(fd, filename, nameBufSize);
+ if (amt == nameBufSize) {
+ snapshot->add(String8(filename, file.nameLen), file);
+ }
+ bytesRead += amt;
+ if (filename != filenameBuf) {
+ free(filename);
+ }
+ if (amt != nameBufSize) {
+ LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
+ return 1;
+ }
+ }
+
+ if (header.totalSize != bytesRead) {
+ LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
+ header.totalSize, bytesRead);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
+{
+ int fileCount = 0;
+ int bytesWritten = sizeof(SnapshotHeader);
+ // preflight size
+ const int N = snapshot.size();
+ for (int i=0; i<N; i++) {
+ const FileRec& g = snapshot.valueAt(i);
+ if (!g.deleted) {
+ const String8& name = snapshot.keyAt(i);
+ bytesWritten += sizeof(FileState) + round_up(name.length());
+ fileCount++;
+ }
+ }
+
+ LOGP("write_snapshot_file fd=%d\n", fd);
+
+ int amt;
+ SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
+
+ amt = write(fd, &header, sizeof(header));
+ if (amt != sizeof(header)) {
+ LOGW("write_snapshot_file error writing header %s", strerror(errno));
+ return errno;
+ }
+
+ for (int i=0; i<N; i++) {
+ FileRec r = snapshot.valueAt(i);
+ if (!r.deleted) {
+ const String8& name = snapshot.keyAt(i);
+ int nameLen = r.s.nameLen = name.length();
+
+ amt = write(fd, &r.s, sizeof(FileState));
+ if (amt != sizeof(FileState)) {
+ LOGW("write_snapshot_file error writing header %s", strerror(errno));
+ return 1;
+ }
+
+ // filename is not NULL terminated, but it is padded
+ amt = write(fd, name.string(), nameLen);
+ if (amt != nameLen) {
+ LOGW("write_snapshot_file error writing filename %s", strerror(errno));
+ return 1;
+ }
+ int paddingLen = ROUND_UP[nameLen % 4];
+ if (paddingLen != 0) {
+ int padding = 0xabababab;
+ amt = write(fd, &padding, paddingLen);
+ if (amt != paddingLen) {
+ LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
+ paddingLen, strerror(errno));
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+write_delete_file(BackupDataWriter* dataStream, const String8& key)
+{
+ LOGP("write_delete_file %s\n", key.string());
+ return dataStream->WriteEntityHeader(key, -1);
+}
+
+static int
+write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
+ char const* realFilename)
+{
+ LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
+
+ const int bufsize = 4*1024;
+ int err;
+ int amt;
+ int fileSize;
+ int bytesLeft;
+ file_metadata_v1 metadata;
+
+ char* buf = (char*)malloc(bufsize);
+ int crc = crc32(0L, Z_NULL, 0);
+
+
+ fileSize = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ if (sizeof(metadata) != 16) {
+ LOGE("ERROR: metadata block is the wrong size!");
+ }
+
+ bytesLeft = fileSize + sizeof(metadata);
+ err = dataStream->WriteEntityHeader(key, bytesLeft);
+ if (err != 0) {
+ free(buf);
+ return err;
+ }
+
+ // store the file metadata first
+ metadata.version = tolel(CURRENT_METADATA_VERSION);
+ metadata.mode = tolel(mode);
+ metadata.undefined_1 = metadata.undefined_2 = 0;
+ err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
+ if (err != 0) {
+ free(buf);
+ return err;
+ }
+ bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
+
+ // now store the file content
+ while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
+ bytesLeft -= amt;
+ if (bytesLeft < 0) {
+ amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
+ }
+ err = dataStream->WriteEntityData(buf, amt);
+ if (err != 0) {
+ free(buf);
+ return err;
+ }
+ }
+ if (bytesLeft != 0) {
+ if (bytesLeft > 0) {
+ // Pad out the space we promised in the buffer. We can't corrupt the buffer,
+ // even though the data we're sending is probably bad.
+ memset(buf, 0, bufsize);
+ while (bytesLeft > 0) {
+ amt = bytesLeft < bufsize ? bytesLeft : bufsize;
+ bytesLeft -= amt;
+ err = dataStream->WriteEntityData(buf, amt);
+ if (err != 0) {
+ free(buf);
+ return err;
+ }
+ }
+ }
+ LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
+ " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
+ }
+
+ free(buf);
+ return NO_ERROR;
+}
+
+static int
+write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
+{
+ int err;
+ struct stat st;
+
+ err = stat(realFilename, &st);
+ if (err < 0) {
+ return errno;
+ }
+
+ int fd = open(realFilename, O_RDONLY);
+ if (fd == -1) {
+ return errno;
+ }
+
+ err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
+ close(fd);
+ return err;
+}
+
+static int
+compute_crc32(int fd)
+{
+ const int bufsize = 4*1024;
+ int amt;
+
+ char* buf = (char*)malloc(bufsize);
+ int crc = crc32(0L, Z_NULL, 0);
+
+ lseek(fd, 0, SEEK_SET);
+
+ while ((amt = read(fd, buf, bufsize)) != 0) {
+ crc = crc32(crc, (Bytef*)buf, amt);
+ }
+
+ free(buf);
+ return crc;
+}
+
+int
+back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
+ char const* const* files, char const* const* keys, int fileCount)
+{
+ int err;
+ KeyedVector<String8,FileState> oldSnapshot;
+ KeyedVector<String8,FileRec> newSnapshot;
+
+ if (oldSnapshotFD != -1) {
+ err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
+ if (err != 0) {
+ // On an error, treat this as a full backup.
+ oldSnapshot.clear();
+ }
+ }
+
+ for (int i=0; i<fileCount; i++) {
+ String8 key(keys[i]);
+ FileRec r;
+ char const* file = files[i];
+ r.file = file;
+ struct stat st;
+
+ err = stat(file, &st);
+ if (err != 0) {
+ r.deleted = true;
+ } else {
+ r.deleted = false;
+ r.s.modTime_sec = st.st_mtime;
+ r.s.modTime_nsec = 0; // workaround sim breakage
+ //r.s.modTime_nsec = st.st_mtime_nsec;
+ r.s.mode = st.st_mode;
+ r.s.size = st.st_size;
+ // we compute the crc32 later down below, when we already have the file open.
+
+ if (newSnapshot.indexOfKey(key) >= 0) {
+ LOGP("back_up_files key already in use '%s'", key.string());
+ return -1;
+ }
+ }
+ newSnapshot.add(key, r);
+ }
+
+ int n = 0;
+ int N = oldSnapshot.size();
+ int m = 0;
+
+ while (n<N && m<fileCount) {
+ const String8& p = oldSnapshot.keyAt(n);
+ const String8& q = newSnapshot.keyAt(m);
+ FileRec& g = newSnapshot.editValueAt(m);
+ int cmp = p.compare(q);
+ if (g.deleted || cmp < 0) {
+ // file removed
+ LOGP("file removed: %s", p.string());
+ g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
+ dataStream->WriteEntityHeader(p, -1);
+ n++;
+ }
+ else if (cmp > 0) {
+ // file added
+ LOGP("file added: %s", g.file.string());
+ write_update_file(dataStream, q, g.file.string());
+ m++;
+ }
+ else {
+ // both files exist, check them
+ const FileState& f = oldSnapshot.valueAt(n);
+
+ int fd = open(g.file.string(), O_RDONLY);
+ if (fd < 0) {
+ // We can't open the file. Don't report it as a delete either. Let the
+ // server keep the old version. Maybe they'll be able to deal with it
+ // on restore.
+ LOGP("Unable to open file %s - skipping", g.file.string());
+ } else {
+ g.s.crc32 = compute_crc32(fd);
+
+ LOGP("%s", q.string());
+ LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
+ f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
+ LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
+ g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
+ if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
+ || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
+ write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
+ }
+
+ close(fd);
+ }
+ n++;
+ m++;
+ }
+ }
+
+ // these were deleted
+ while (n<N) {
+ dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
+ n++;
+ }
+
+ // these were added
+ while (m<fileCount) {
+ const String8& q = newSnapshot.keyAt(m);
+ FileRec& g = newSnapshot.editValueAt(m);
+ write_update_file(dataStream, q, g.file.string());
+ m++;
+ }
+
+ err = write_snapshot_file(newSnapshotFD, newSnapshot);
+
+ return 0;
+}
+
+#define RESTORE_BUF_SIZE (8*1024)
+
+RestoreHelperBase::RestoreHelperBase()
+{
+ m_buf = malloc(RESTORE_BUF_SIZE);
+ m_loggedUnknownMetadata = false;
+}
+
+RestoreHelperBase::~RestoreHelperBase()
+{
+ free(m_buf);
+}
+
+status_t
+RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
+{
+ ssize_t err;
+ size_t dataSize;
+ String8 key;
+ int fd;
+ void* buf = m_buf;
+ ssize_t amt;
+ int mode;
+ int crc;
+ struct stat st;
+ FileRec r;
+
+ err = in->ReadEntityHeader(&key, &dataSize);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // Get the metadata block off the head of the file entity and use that to
+ // set up the output file
+ file_metadata_v1 metadata;
+ amt = in->ReadEntityData(&metadata, sizeof(metadata));
+ if (amt != sizeof(metadata)) {
+ LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
+ (long)amt, strerror(errno));
+ return EIO;
+ }
+ metadata.version = fromlel(metadata.version);
+ metadata.mode = fromlel(metadata.mode);
+ if (metadata.version > CURRENT_METADATA_VERSION) {
+ if (!m_loggedUnknownMetadata) {
+ m_loggedUnknownMetadata = true;
+ LOGW("Restoring file with unsupported metadata version %d (currently %d)",
+ metadata.version, CURRENT_METADATA_VERSION);
+ }
+ }
+ mode = metadata.mode;
+
+ // Write the file and compute the crc
+ crc = crc32(0L, Z_NULL, 0);
+ fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
+ if (fd == -1) {
+ LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
+ return errno;
+ }
+
+ while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
+ err = write(fd, buf, amt);
+ if (err != amt) {
+ close(fd);
+ LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
+ return errno;
+ }
+ crc = crc32(crc, (Bytef*)buf, amt);
+ }
+
+ close(fd);
+
+ // Record for the snapshot
+ err = stat(filename.string(), &st);
+ if (err != 0) {
+ LOGW("Error stating file that we just created %s", filename.string());
+ return errno;
+ }
+
+ r.file = filename;
+ r.deleted = false;
+ r.s.modTime_sec = st.st_mtime;
+ r.s.modTime_nsec = 0; // workaround sim breakage
+ //r.s.modTime_nsec = st.st_mtime_nsec;
+ r.s.mode = st.st_mode;
+ r.s.size = st.st_size;
+ r.s.crc32 = crc;
+
+ m_files.add(key, r);
+
+ return NO_ERROR;
+}
+
+status_t
+RestoreHelperBase::WriteSnapshot(int fd)
+{
+ return write_snapshot_file(fd, m_files);;
+}
+
+#if TEST_BACKUP_HELPERS
+
+#define SCRATCH_DIR "/data/backup_helper_test/"
+
+static int
+write_text_file(const char* path, const char* data)
+{
+ int amt;
+ int fd;
+ int len;
+
+ fd = creat(path, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "creat %s failed\n", path);
+ return errno;
+ }
+
+ len = strlen(data);
+ amt = write(fd, data, len);
+ if (amt != len) {
+ fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
+ return errno;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+static int
+compare_file(const char* path, const unsigned char* data, int len)
+{
+ int fd;
+ int amt;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
+ return errno;
+ }
+
+ unsigned char* contents = (unsigned char*)malloc(len);
+ if (contents == NULL) {
+ fprintf(stderr, "malloc(%d) failed\n", len);
+ return ENOMEM;
+ }
+
+ bool sizesMatch = true;
+ amt = lseek(fd, 0, SEEK_END);
+ if (amt != len) {
+ fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
+ sizesMatch = false;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ int readLen = amt < len ? amt : len;
+ amt = read(fd, contents, readLen);
+ if (amt != readLen) {
+ fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
+ }
+
+ bool contentsMatch = true;
+ for (int i=0; i<readLen; i++) {
+ if (data[i] != contents[i]) {
+ if (contentsMatch) {
+ fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
+ contentsMatch = false;
+ }
+ fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
+ }
+ }
+
+ free(contents);
+ return contentsMatch && sizesMatch ? 0 : 1;
+}
+
+int
+backup_helper_test_empty()
+{
+ int err;
+ int fd;
+ KeyedVector<String8,FileRec> snapshot;
+ const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+
+ // write
+ fd = creat(filename, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "error creating %s\n", filename);
+ return 1;
+ }
+
+ err = write_snapshot_file(fd, snapshot);
+
+ close(fd);
+
+ if (err != 0) {
+ fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
+ return err;
+ }
+
+ static const unsigned char correct_data[] = {
+ 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
+ };
+
+ err = compare_file(filename, correct_data, sizeof(correct_data));
+ if (err != 0) {
+ return err;
+ }
+
+ // read
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "error opening for read %s\n", filename);
+ return 1;
+ }
+
+ KeyedVector<String8,FileState> readSnapshot;
+ err = read_snapshot_file(fd, &readSnapshot);
+ if (err != 0) {
+ fprintf(stderr, "read_snapshot_file failed %d\n", err);
+ return err;
+ }
+
+ if (readSnapshot.size() != 0) {
+ fprintf(stderr, "readSnapshot should be length 0\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+backup_helper_test_four()
+{
+ int err;
+ int fd;
+ KeyedVector<String8,FileRec> snapshot;
+ const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+
+ // write
+ fd = creat(filename, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "error opening %s\n", filename);
+ return 1;
+ }
+
+ String8 filenames[4];
+ FileState states[4];
+ FileRec r;
+ r.deleted = false;
+
+ states[0].modTime_sec = 0xfedcba98;
+ states[0].modTime_nsec = 0xdeadbeef;
+ states[0].mode = 0777; // decimal 511, hex 0x000001ff
+ states[0].size = 0xababbcbc;
+ states[0].crc32 = 0x12345678;
+ states[0].nameLen = -12;
+ r.s = states[0];
+ filenames[0] = String8("bytes_of_padding");
+ snapshot.add(filenames[0], r);
+
+ states[1].modTime_sec = 0x93400031;
+ states[1].modTime_nsec = 0xdeadbeef;
+ states[1].mode = 0666; // decimal 438, hex 0x000001b6
+ states[1].size = 0x88557766;
+ states[1].crc32 = 0x22334422;
+ states[1].nameLen = -1;
+ r.s = states[1];
+ filenames[1] = String8("bytes_of_padding3");
+ snapshot.add(filenames[1], r);
+
+ states[2].modTime_sec = 0x33221144;
+ states[2].modTime_nsec = 0xdeadbeef;
+ states[2].mode = 0744; // decimal 484, hex 0x000001e4
+ states[2].size = 0x11223344;
+ states[2].crc32 = 0x01122334;
+ states[2].nameLen = 0;
+ r.s = states[2];
+ filenames[2] = String8("bytes_of_padding_2");
+ snapshot.add(filenames[2], r);
+
+ states[3].modTime_sec = 0x33221144;
+ states[3].modTime_nsec = 0xdeadbeef;
+ states[3].mode = 0755; // decimal 493, hex 0x000001ed
+ states[3].size = 0x11223344;
+ states[3].crc32 = 0x01122334;
+ states[3].nameLen = 0;
+ r.s = states[3];
+ filenames[3] = String8("bytes_of_padding__1");
+ snapshot.add(filenames[3], r);
+
+ err = write_snapshot_file(fd, snapshot);
+
+ close(fd);
+
+ if (err != 0) {
+ fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
+ return err;
+ }
+
+ static const unsigned char correct_data[] = {
+ // header
+ 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
+ 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
+
+ // bytes_of_padding
+ 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
+ 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
+ 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
+ 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
+ 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
+
+ // bytes_of_padding3
+ 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
+ 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
+ 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
+ 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
+ 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
+ 0x33, 0xab, 0xab, 0xab,
+
+ // bytes of padding2
+ 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
+ 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
+ 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
+ 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
+ 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
+ 0x5f, 0x32, 0xab, 0xab,
+
+ // bytes of padding3
+ 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
+ 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
+ 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
+ 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
+ 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
+ 0x5f, 0x5f, 0x31, 0xab
+ };
+
+ err = compare_file(filename, correct_data, sizeof(correct_data));
+ if (err != 0) {
+ return err;
+ }
+
+ // read
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "error opening for read %s\n", filename);
+ return 1;
+ }
+
+
+ KeyedVector<String8,FileState> readSnapshot;
+ err = read_snapshot_file(fd, &readSnapshot);
+ if (err != 0) {
+ fprintf(stderr, "read_snapshot_file failed %d\n", err);
+ return err;
+ }
+
+ if (readSnapshot.size() != 4) {
+ fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
+ return 1;
+ }
+
+ bool matched = true;
+ for (size_t i=0; i<readSnapshot.size(); i++) {
+ const String8& name = readSnapshot.keyAt(i);
+ const FileState state = readSnapshot.valueAt(i);
+
+ if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
+ || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
+ || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
+ fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
+ " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
+ states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
+ states[i].crc32, name.length(), filenames[i].string(),
+ state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
+ state.nameLen, name.string());
+ matched = false;
+ }
+ }
+
+ return matched ? 0 : 1;
+}
+
+// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
+const unsigned char DATA_GOLDEN_FILE[] = {
+ 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
+ 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
+ 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
+ 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+ 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
+ 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
+ 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
+ 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
+ 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
+
+};
+const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
+
+static int
+test_write_header_and_entity(BackupDataWriter& writer, const char* str)
+{
+ int err;
+ String8 text(str);
+
+ err = writer.WriteEntityHeader(text, text.length()+1);
+ if (err != 0) {
+ fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
+ return err;
+ }
+
+ err = writer.WriteEntityData(text.string(), text.length()+1);
+ if (err != 0) {
+ fprintf(stderr, "write failed for data '%s'\n", text.string());
+ return errno;
+ }
+
+ return err;
+}
+
+int
+backup_helper_test_data_writer()
+{
+ int err;
+ int fd;
+ const char* filename = SCRATCH_DIR "data_writer.data";
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+ mkdir(SCRATCH_DIR "data", 0777);
+
+ fd = creat(filename, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ BackupDataWriter writer(fd);
+
+ err = 0;
+ err |= test_write_header_and_entity(writer, "no_padding_");
+ err |= test_write_header_and_entity(writer, "padded_to__3");
+ err |= test_write_header_and_entity(writer, "padded_to_2__");
+ err |= test_write_header_and_entity(writer, "padded_to1");
+
+ close(fd);
+
+ err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
+ if (err != 0) {
+ return err;
+ }
+
+ return err;
+}
+
+int
+test_read_header_and_entity(BackupDataReader& reader, const char* str)
+{
+ int err;
+ int bufSize = strlen(str)+1;
+ char* buf = (char*)malloc(bufSize);
+ String8 string;
+ int cookie = 0x11111111;
+ size_t actualSize;
+ bool done;
+ int type;
+ ssize_t nRead;
+
+ // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
+
+ err = reader.ReadNextHeader(&done, &type);
+ if (done) {
+ fprintf(stderr, "should not be done yet\n");
+ goto finished;
+ }
+ if (err != 0) {
+ fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
+ goto finished;
+ }
+ if (type != BACKUP_HEADER_ENTITY_V1) {
+ err = EINVAL;
+ fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
+ }
+
+ err = reader.ReadEntityHeader(&string, &actualSize);
+ if (err != 0) {
+ fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
+ goto finished;
+ }
+ if (string != str) {
+ fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
+ err = EINVAL;
+ goto finished;
+ }
+ if ((int)actualSize != bufSize) {
+ fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
+ actualSize);
+ err = EINVAL;
+ goto finished;
+ }
+
+ nRead = reader.ReadEntityData(buf, bufSize);
+ if (nRead < 0) {
+ err = reader.Status();
+ fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
+ goto finished;
+ }
+
+ if (0 != memcmp(buf, str, bufSize)) {
+ fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
+ "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
+ buf[0], buf[1], buf[2], buf[3]);
+ err = EINVAL;
+ goto finished;
+ }
+
+ // The next read will confirm whether it got the right amount of data.
+
+finished:
+ if (err != NO_ERROR) {
+ fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
+ }
+ free(buf);
+ return err;
+}
+
+int
+backup_helper_test_data_reader()
+{
+ int err;
+ int fd;
+ const char* filename = SCRATCH_DIR "data_reader.data";
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+ mkdir(SCRATCH_DIR "data", 0777);
+
+ fd = creat(filename, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
+ if (err != DATA_GOLDEN_FILE_SIZE) {
+ fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
+ return errno;
+ }
+
+ close(fd);
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
+ filename);
+ return errno;
+ }
+
+ {
+ BackupDataReader reader(fd);
+
+ err = 0;
+
+ if (err == NO_ERROR) {
+ err = test_read_header_and_entity(reader, "no_padding_");
+ }
+
+ if (err == NO_ERROR) {
+ err = test_read_header_and_entity(reader, "padded_to__3");
+ }
+
+ if (err == NO_ERROR) {
+ err = test_read_header_and_entity(reader, "padded_to_2__");
+ }
+
+ if (err == NO_ERROR) {
+ err = test_read_header_and_entity(reader, "padded_to1");
+ }
+ }
+
+ close(fd);
+
+ return err;
+}
+
+static int
+get_mod_time(const char* filename, struct timeval times[2])
+{
+ int err;
+ struct stat64 st;
+ err = stat64(filename, &st);
+ if (err != 0) {
+ fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
+ return errno;
+ }
+ times[0].tv_sec = st.st_atime;
+ times[1].tv_sec = st.st_mtime;
+
+ // If st_atime is a macro then struct stat64 uses struct timespec
+ // to store the access and modif time values and typically
+ // st_*time_nsec is not defined. In glibc, this is controlled by
+ // __USE_MISC.
+#ifdef __USE_MISC
+#if !defined(st_atime) || defined(st_atime_nsec)
+#error "Check if this __USE_MISC conditional is still needed."
+#endif
+ times[0].tv_usec = st.st_atim.tv_nsec / 1000;
+ times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
+#else
+ times[0].tv_usec = st.st_atime_nsec / 1000;
+ times[1].tv_usec = st.st_mtime_nsec / 1000;
+#endif
+
+ return 0;
+}
+
+int
+backup_helper_test_files()
+{
+ int err;
+ int oldSnapshotFD;
+ int dataStreamFD;
+ int newSnapshotFD;
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+ mkdir(SCRATCH_DIR "data", 0777);
+
+ write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
+ write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
+ write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
+ write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
+ write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
+ write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
+
+ char const* files_before[] = {
+ SCRATCH_DIR "data/b",
+ SCRATCH_DIR "data/c",
+ SCRATCH_DIR "data/d",
+ SCRATCH_DIR "data/e",
+ SCRATCH_DIR "data/f"
+ };
+
+ char const* keys_before[] = {
+ "data/b",
+ "data/c",
+ "data/d",
+ "data/e",
+ "data/f"
+ };
+
+ dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
+ if (dataStreamFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
+ if (newSnapshotFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ {
+ BackupDataWriter dataStream(dataStreamFD);
+
+ err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
+ if (err != 0) {
+ return err;
+ }
+ }
+
+ close(dataStreamFD);
+ close(newSnapshotFD);
+
+ sleep(3);
+
+ struct timeval d_times[2];
+ struct timeval e_times[2];
+
+ err = get_mod_time(SCRATCH_DIR "data/d", d_times);
+ err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
+ if (err != 0) {
+ return err;
+ }
+
+ write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
+ unlink(SCRATCH_DIR "data/c");
+ write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
+ write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
+ utimes(SCRATCH_DIR "data/d", d_times);
+ write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
+ utimes(SCRATCH_DIR "data/e", e_times);
+ write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
+ unlink(SCRATCH_DIR "data/f");
+
+ char const* files_after[] = {
+ SCRATCH_DIR "data/a", // added
+ SCRATCH_DIR "data/b", // same
+ SCRATCH_DIR "data/c", // different mod time
+ SCRATCH_DIR "data/d", // different size (same mod time)
+ SCRATCH_DIR "data/e", // different contents (same mod time, same size)
+ SCRATCH_DIR "data/g" // added
+ };
+
+ char const* keys_after[] = {
+ "data/a", // added
+ "data/b", // same
+ "data/c", // different mod time
+ "data/d", // different size (same mod time)
+ "data/e", // different contents (same mod time, same size)
+ "data/g" // added
+ };
+
+ oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
+ if (oldSnapshotFD == -1) {
+ fprintf(stderr, "error opening: %s\n", strerror(errno));
+ return errno;
+ }
+
+ dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
+ if (dataStreamFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
+ if (newSnapshotFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ {
+ BackupDataWriter dataStream(dataStreamFD);
+
+ err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
+ if (err != 0) {
+ return err;
+ }
+}
+
+ close(oldSnapshotFD);
+ close(dataStreamFD);
+ close(newSnapshotFD);
+
+ return 0;
+}
+
+int
+backup_helper_test_null_base()
+{
+ int err;
+ int oldSnapshotFD;
+ int dataStreamFD;
+ int newSnapshotFD;
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+ mkdir(SCRATCH_DIR "data", 0777);
+
+ write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
+
+ char const* files[] = {
+ SCRATCH_DIR "data/a",
+ };
+
+ char const* keys[] = {
+ "a",
+ };
+
+ dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
+ if (dataStreamFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
+ if (newSnapshotFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ {
+ BackupDataWriter dataStream(dataStreamFD);
+
+ err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
+ if (err != 0) {
+ return err;
+ }
+ }
+
+ close(dataStreamFD);
+ close(newSnapshotFD);
+
+ return 0;
+}
+
+int
+backup_helper_test_missing_file()
+{
+ int err;
+ int oldSnapshotFD;
+ int dataStreamFD;
+ int newSnapshotFD;
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+ mkdir(SCRATCH_DIR "data", 0777);
+
+ write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
+
+ char const* files[] = {
+ SCRATCH_DIR "data/a",
+ SCRATCH_DIR "data/b",
+ SCRATCH_DIR "data/c",
+ };
+
+ char const* keys[] = {
+ "a",
+ "b",
+ "c",
+ };
+
+ dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
+ if (dataStreamFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
+ if (newSnapshotFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ {
+ BackupDataWriter dataStream(dataStreamFD);
+
+ err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
+ if (err != 0) {
+ return err;
+ }
+ }
+
+ close(dataStreamFD);
+ close(newSnapshotFD);
+
+ return 0;
+}
+
+
+#endif // TEST_BACKUP_HELPERS
+
+}
diff --git a/libs/utils/characterData.h b/libs/utils/CharacterData.h
similarity index 100%
rename from libs/utils/characterData.h
rename to libs/utils/CharacterData.h
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
index 0f4b647..b0e3750 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/utils/Parcel.cpp
@@ -409,12 +409,16 @@
mObjects[idx++] = off;
mObjectsSize++;
- const flat_binder_object* flat
+ flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(mData + off);
acquire_object(proc, *flat, this);
- // take note if the object is a file descriptor
if (flat->type == BINDER_TYPE_FD) {
+ // If this is a file descriptor, we need to dup it so the
+ // new Parcel now owns its own fd, and can declare that we
+ // officially know we have fds.
+ flat->handle = dup(flat->handle);
+ flat->cookie = (void*)1;
mHasFds = mFdsKnown = true;
}
}
@@ -650,28 +654,26 @@
return flatten_binder(ProcessState::self(), val, this);
}
-status_t Parcel::writeNativeHandle(const native_handle& handle)
+status_t Parcel::writeNativeHandle(const native_handle* handle)
{
- if (handle.version != sizeof(native_handle))
+ if (handle->version != sizeof(native_handle))
return BAD_TYPE;
status_t err;
- err = writeInt32(handle.numFds);
+ err = writeInt32(handle->numFds);
if (err != NO_ERROR) return err;
- err = writeInt32(handle.numInts);
+ err = writeInt32(handle->numInts);
if (err != NO_ERROR) return err;
- for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++)
- err = writeDupFileDescriptor(handle.data[i]);
+ for (int i=0 ; err==NO_ERROR && i<handle->numFds ; i++)
+ err = writeDupFileDescriptor(handle->data[i]);
if (err != NO_ERROR) {
LOGD("write native handle, write dup fd failed");
return err;
}
-
- err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts);
-
+ err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts);
return err;
}
@@ -928,7 +930,7 @@
}
-native_handle* Parcel::readNativeHandle(native_handle* (*alloc)(void*, int, int), void* cookie) const
+native_handle* Parcel::readNativeHandle() const
{
int numFds, numInts;
status_t err;
@@ -937,31 +939,15 @@
err = readInt32(&numInts);
if (err != NO_ERROR) return 0;
- native_handle* h;
- if (alloc == 0) {
- size_t size = sizeof(native_handle) + sizeof(int)*(numFds + numInts);
- h = (native_handle*)malloc(size);
- h->version = sizeof(native_handle);
- h->numFds = numFds;
- h->numInts = numInts;
- } else {
- h = alloc(cookie, numFds, numInts);
- if (h->version != sizeof(native_handle)) {
- return 0;
- }
- }
-
+ native_handle* h = native_handle_create(numFds, numInts);
for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
h->data[i] = dup(readFileDescriptor());
if (h->data[i] < 0) err = BAD_VALUE;
}
-
err = read(h->data + numFds, sizeof(int)*numInts);
-
if (err != NO_ERROR) {
- if (alloc == 0) {
- free(h);
- }
+ native_handle_close(h);
+ native_handle_delete(h);
h = 0;
}
return h;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 3d12dca..109f28d 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -544,7 +544,7 @@
return mEventCode;
}
-const int32_t ResXMLParser::getCommentID() const
+int32_t ResXMLParser::getCommentID() const
{
return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
}
@@ -555,12 +555,12 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
-const uint32_t ResXMLParser::getLineNumber() const
+uint32_t ResXMLParser::getLineNumber() const
{
return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
}
-const int32_t ResXMLParser::getTextID() const
+int32_t ResXMLParser::getTextID() const
{
if (mEventCode == TEXT) {
return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
@@ -583,7 +583,7 @@
return BAD_TYPE;
}
-const int32_t ResXMLParser::getNamespacePrefixID() const
+int32_t ResXMLParser::getNamespacePrefixID() const
{
if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
@@ -598,7 +598,7 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
-const int32_t ResXMLParser::getNamespaceUriID() const
+int32_t ResXMLParser::getNamespaceUriID() const
{
if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
@@ -613,7 +613,7 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
-const int32_t ResXMLParser::getElementNamespaceID() const
+int32_t ResXMLParser::getElementNamespaceID() const
{
if (mEventCode == START_TAG) {
return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
@@ -630,7 +630,7 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
-const int32_t ResXMLParser::getElementNameID() const
+int32_t ResXMLParser::getElementNameID() const
{
if (mEventCode == START_TAG) {
return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
@@ -655,7 +655,7 @@
return 0;
}
-const int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
+int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
{
if (mEventCode == START_TAG) {
const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -678,7 +678,7 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
-const int32_t ResXMLParser::getAttributeNameID(size_t idx) const
+int32_t ResXMLParser::getAttributeNameID(size_t idx) const
{
if (mEventCode == START_TAG) {
const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -701,7 +701,7 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
-const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
+uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
{
int32_t id = getAttributeNameID(idx);
if (id >= 0 && (size_t)id < mTree.mNumResIds) {
@@ -710,7 +710,7 @@
return 0;
}
-const int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
+int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
{
if (mEventCode == START_TAG) {
const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -1136,8 +1136,9 @@
struct ResTable::Header
{
- Header() : ownedData(NULL), header(NULL) { }
+ Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
+ ResTable* const owner;
void* ownedData;
const ResTable_header* header;
size_t size;
@@ -1163,8 +1164,8 @@
struct ResTable::Package
{
- Package(const Header* _header, const ResTable_package* _package)
- : header(_header), package(_package) { }
+ Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
+ : owner(_owner), header(_header), package(_package) { }
~Package()
{
size_t i = types.size();
@@ -1174,10 +1175,14 @@
}
}
+ ResTable* const owner;
const Header* const header;
const ResTable_package* const package;
Vector<Type*> types;
+ ResStringPool typeStrings;
+ ResStringPool keyStrings;
+
const Type* getType(size_t idx) const {
return idx < types.size() ? types[idx] : NULL;
}
@@ -1188,13 +1193,16 @@
// table that defined the package); the ones after are skins on top of it.
struct ResTable::PackageGroup
{
- PackageGroup(const String16& _name, uint32_t _id)
- : name(_name), id(_id), typeCount(0), bags(NULL) { }
+ PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
+ : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
~PackageGroup() {
clearBagCache();
const size_t N = packages.size();
for (size_t i=0; i<N; i++) {
- delete packages[i];
+ Package* pkg = packages[i];
+ if (pkg->owner == owner) {
+ delete pkg;
+ }
}
}
@@ -1225,15 +1233,17 @@
}
}
+ ResTable* const owner;
String16 const name;
uint32_t const id;
Vector<Package*> packages;
+
+ // This is for finding typeStrings and other common package stuff.
+ Package* basePackage;
- // Taken from the root package.
- ResStringPool typeStrings;
- ResStringPool keyStrings;
+ // For quick access.
size_t typeCount;
-
+
// Computed attribute bags, first indexed by the type and second
// by the entry in that type.
bag_set*** bags;
@@ -1560,11 +1570,36 @@
return add(data, size, cookie, asset, copyData);
}
+status_t ResTable::add(ResTable* src)
+{
+ mError = src->mError;
+ mParams = src->mParams;
+
+ for (size_t i=0; i<src->mHeaders.size(); i++) {
+ mHeaders.add(src->mHeaders[i]);
+ }
+
+ for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+ PackageGroup* srcPg = src->mPackageGroups[i];
+ PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
+ for (size_t j=0; j<srcPg->packages.size(); j++) {
+ pg->packages.add(srcPg->packages[j]);
+ }
+ pg->basePackage = srcPg->basePackage;
+ pg->typeCount = srcPg->typeCount;
+ mPackageGroups.add(pg);
+ }
+
+ memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
+
+ return mError;
+}
+
status_t ResTable::add(const void* data, size_t size, void* cookie,
Asset* asset, bool copyData)
{
if (!data) return NO_ERROR;
- Header* header = new Header;
+ Header* header = new Header(this);
header->index = mHeaders.size();
header->cookie = cookie;
mHeaders.add(header);
@@ -1682,10 +1717,12 @@
N = mHeaders.size();
for (size_t i=0; i<N; i++) {
Header* header = mHeaders[i];
- if (header->ownedData) {
- free(header->ownedData);
+ if (header->owner == this) {
+ if (header->ownedData) {
+ free(header->ownedData);
+ }
+ delete header;
}
- delete header;
}
mPackageGroups.clear();
@@ -1728,8 +1765,8 @@
outName->package = grp->name.string();
outName->packageLen = grp->name.size();
- outName->type = grp->typeStrings.stringAt(t, &outName->typeLen);
- outName->name = grp->keyStrings.stringAt(
+ outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
+ outName->name = grp->basePackage->keyStrings.stringAt(
dtohl(entry->key.index), &outName->nameLen);
return true;
}
@@ -2331,13 +2368,13 @@
continue;
}
- const ssize_t ti = group->typeStrings.indexOfString(type, typeLen);
+ const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
if (ti < 0) {
TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
continue;
}
- const ssize_t ei = group->keyStrings.indexOfString(name, nameLen);
+ const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
if (ei < 0) {
TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
continue;
@@ -3630,25 +3667,36 @@
PackageGroup* group = NULL;
uint32_t id = dtohl(pkg->id);
if (id != 0 && id < 256) {
+
+ package = new Package(this, header, pkg);
+ if (package == NULL) {
+ return (mError=NO_MEMORY);
+ }
+
size_t idx = mPackageMap[id];
if (idx == 0) {
idx = mPackageGroups.size()+1;
char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
- group = new PackageGroup(String16(tmpName), id);
+ group = new PackageGroup(this, String16(tmpName), id);
if (group == NULL) {
+ delete package;
return (mError=NO_MEMORY);
}
- err = group->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+ err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
header->dataEnd-(base+dtohl(pkg->typeStrings)));
if (err != NO_ERROR) {
+ delete group;
+ delete package;
return (mError=err);
}
- err = group->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+ err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
header->dataEnd-(base+dtohl(pkg->keyStrings)));
if (err != NO_ERROR) {
+ delete group;
+ delete package;
return (mError=err);
}
@@ -3657,6 +3705,8 @@
if (err < NO_ERROR) {
return (mError=err);
}
+ group->basePackage = package;
+
mPackageMap[id] = (uint8_t)idx;
} else {
group = mPackageGroups.itemAt(idx-1);
@@ -3664,10 +3714,6 @@
return (mError=UNKNOWN_ERROR);
}
}
- package = new Package(header, pkg);
- if (package == NULL) {
- return (mError=NO_MEMORY);
- }
err = group->packages.add(package);
if (err < NO_ERROR) {
return (mError=err);
@@ -3830,9 +3876,88 @@
#define CHAR16_ARRAY_EQ(constant, var, len) \
((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
-void ResTable::print() const
+void print_complex(uint32_t complex, bool isFraction)
{
- printf("mError=0x%x (%s)\n", mError, strerror(mError));
+ const float MANTISSA_MULT =
+ 1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
+ const float RADIX_MULTS[] = {
+ 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
+ 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
+ };
+
+ float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
+ <<Res_value::COMPLEX_MANTISSA_SHIFT))
+ * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
+ & Res_value::COMPLEX_RADIX_MASK];
+ printf("%f", value);
+
+ if (!isFraction) {
+ switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+ case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
+ case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
+ case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
+ case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
+ case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
+ case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
+ default: printf(" (unknown unit)"); break;
+ }
+ } else {
+ switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+ case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
+ case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
+ default: printf(" (unknown unit)"); break;
+ }
+ }
+}
+
+void ResTable::print_value(const Package* pkg, const Res_value& value) const
+{
+ if (value.dataType == Res_value::TYPE_NULL) {
+ printf("(null)\n");
+ } else if (value.dataType == Res_value::TYPE_REFERENCE) {
+ printf("(reference) 0x%08x\n", value.data);
+ } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
+ printf("(attribute) 0x%08x\n", value.data);
+ } else if (value.dataType == Res_value::TYPE_STRING) {
+ size_t len;
+ const char16_t* str = pkg->header->values.stringAt(
+ value.data, &len);
+ if (str == NULL) {
+ printf("(string) null\n");
+ } else {
+ printf("(string) \"%s\"\n",
+ String8(str, len).string());
+ }
+ } else if (value.dataType == Res_value::TYPE_FLOAT) {
+ printf("(float) %g\n", *(const float*)&value.data);
+ } else if (value.dataType == Res_value::TYPE_DIMENSION) {
+ printf("(dimension) ");
+ print_complex(value.data, false);
+ printf("\n");
+ } else if (value.dataType == Res_value::TYPE_FRACTION) {
+ printf("(fraction) ");
+ print_complex(value.data, true);
+ printf("\n");
+ } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
+ || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
+ printf("(color) #%08x\n", value.data);
+ } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
+ printf("(boolean) %s\n", value.data ? "true" : "false");
+ } else if (value.dataType >= Res_value::TYPE_FIRST_INT
+ || value.dataType <= Res_value::TYPE_LAST_INT) {
+ printf("(int) 0x%08x or %d\n", value.data, value.data);
+ } else {
+ printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
+ (int)value.dataType, (int)value.data,
+ (int)value.size, (int)value.res0);
+ }
+}
+
+void ResTable::print(bool inclValues) const
+{
+ if (mError != 0) {
+ printf("mError=0x%x (%s)\n", mError, strerror(mError));
+ }
#if 0
printf("mParams=%c%c-%c%c,\n",
mParams.language[0], mParams.language[1],
@@ -3883,7 +4008,7 @@
printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
continue;
}
- printf(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d\n",
+ printf(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d lyt=%d\n",
(int)configIndex,
type->config.language[0] ? type->config.language[0] : '-',
type->config.language[1] ? type->config.language[1] : '-',
@@ -3896,7 +4021,8 @@
type->config.inputFlags,
type->config.navigation,
dtohs(type->config.screenWidth),
- dtohs(type->config.screenHeight));
+ dtohs(type->config.screenHeight),
+ type->config.screenLayout);
size_t entryCount = dtohl(type->entryCount);
uint32_t entriesStart = dtohl(type->entriesStart);
if ((entriesStart&0x3) != 0) {
@@ -3947,32 +4073,60 @@
(void*)(entriesStart + thisOffset));
continue;
}
+
+ uint16_t esize = dtohs(ent->size);
+ if ((esize&0x3) != 0) {
+ printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
+ continue;
+ }
+ if ((thisOffset+esize) > typeSize) {
+ printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
+ (void*)entriesStart, (void*)thisOffset,
+ (void*)esize, (void*)typeSize);
+ continue;
+ }
+
+ const Res_value* valuePtr = NULL;
+ const ResTable_map_entry* bagPtr = NULL;
+ Res_value value;
if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
printf("<bag>");
+ bagPtr = (const ResTable_map_entry*)ent;
} else {
- uint16_t esize = dtohs(ent->size);
- if ((esize&0x3) != 0) {
- printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
- continue;
- }
- if ((thisOffset+esize) > typeSize) {
- printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
- (void*)entriesStart, (void*)thisOffset,
- (void*)esize, (void*)typeSize);
- continue;
- }
-
- const Res_value* value = (const Res_value*)
+ valuePtr = (const Res_value*)
(((const uint8_t*)ent) + esize);
+ value.copyFrom_dtoh(*valuePtr);
printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
- (int)value->dataType, (int)dtohl(value->data),
- (int)dtohs(value->size), (int)value->res0);
+ (int)value.dataType, (int)value.data,
+ (int)value.size, (int)value.res0);
}
if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
printf(" (PUBLIC)");
}
printf("\n");
+
+ if (inclValues) {
+ if (valuePtr != NULL) {
+ printf(" ");
+ print_value(pkg, value);
+ } else if (bagPtr != NULL) {
+ const int N = dtohl(bagPtr->count);
+ const ResTable_map* mapPtr = (const ResTable_map*)
+ (((const uint8_t*)ent) + esize);
+ printf(" Parent=0x%08x, Count=%d\n",
+ dtohl(bagPtr->parent.ident), N);
+ for (int i=0; i<N; i++) {
+ printf(" #%i (Key=0x%08x): ",
+ i, dtohl(mapPtr->name.ident));
+ value.copyFrom_dtoh(mapPtr->value);
+ print_value(pkg, value);
+ const size_t size = dtohs(mapPtr->value.size);
+ mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
+ + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
+ }
+ }
+ }
}
}
}
diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp
index 33f535f..f92703e 100644
--- a/libs/utils/Unicode.cpp
+++ b/libs/utils/Unicode.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "utils/AndroidUnicode.h"
-#include "characterData.h"
+#include <utils/AndroidUnicode.h>
+#include "CharacterData.h"
#define LOG_TAG "Unicode"
-#include "utils/Log.h"
+#include <utils/Log.h>
// ICU headers for using macros
#include <unicode/utf16.h>
diff --git a/libs/utils/ZipEntry.cpp b/libs/utils/ZipEntry.cpp
index fbc9e67..96f9fc4 100644
--- a/libs/utils/ZipEntry.cpp
+++ b/libs/utils/ZipEntry.cpp
@@ -20,8 +20,8 @@
#define LOG_TAG "zip"
-#include "utils/ZipEntry.h"
-#include "utils/Log.h"
+#include <utils/ZipEntry.h>
+#include <utils/Log.h>
#include <stdio.h>
#include <string.h>
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
index 89aa874..6f27d17 100644
--- a/libs/utils/ZipFile.cpp
+++ b/libs/utils/ZipFile.cpp
@@ -20,9 +20,9 @@
#define LOG_TAG "zip"
-#include "utils/ZipFile.h"
-#include "utils/ZipUtils.h"
-#include "utils/Log.h"
+#include <utils/ZipFile.h>
+#include <utils/ZipUtils.h>
+#include <utils/Log.h>
#include <zlib.h>
#define DEF_MEM_LEVEL 8 // normally in zutil.h?
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
index d312daf..45f6c8b 100644
--- a/libs/utils/ZipFileCRO.cpp
+++ b/libs/utils/ZipFileCRO.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "utils/ZipFileCRO.h"
-#include "utils/ZipFileRO.h"
+#include <utils/ZipFileCRO.h>
+#include <utils/ZipFileRO.h>
using namespace android;
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index ae8c719..6c701dd 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -19,9 +19,9 @@
//
#define LOG_TAG "zipro"
//#define LOG_NDEBUG 0
-#include "utils/ZipFileRO.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
+#include <utils/ZipFileRO.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
#include <zlib.h>
diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp
index bfbacfe..5df94cb 100644
--- a/libs/utils/ZipUtils.cpp
+++ b/libs/utils/ZipUtils.cpp
@@ -20,9 +20,9 @@
#define LOG_TAG "ziputil"
-#include "utils/ZipUtils.h"
-#include "utils/ZipFileRO.h"
-#include "utils/Log.h"
+#include <utils/ZipUtils.h>
+#include <utils/ZipFileRO.h>
+#include <utils/Log.h>
#include <stdlib.h>
#include <string.h>
diff --git a/libs/utils/file_backup_helper.cpp b/libs/utils/file_backup_helper.cpp
deleted file mode 100644
index 453084a..0000000
--- a/libs/utils/file_backup_helper.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
-#define LOG_TAG "file_backup_helper"
-
-#include <utils/backup_helpers.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/ByteOrder.h>
-#include <utils/String8.h>
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <utime.h>
-#include <fcntl.h>
-#include <zlib.h>
-
-#include <cutils/log.h>
-
-using namespace android;
-
-#define MAGIC0 0x70616e53 // Snap
-#define MAGIC1 0x656c6946 // File
-
-#define LOGP(x...) LOGD(x)
-//#define LOGP(x...) printf(x)
-
-struct SnapshotHeader {
- int magic0;
- int fileCount;
- int magic1;
- int totalSize;
-};
-
-struct FileState {
- int modTime_sec;
- int modTime_nsec;
- int size;
- int crc32;
- int nameLen;
-};
-
-const static int ROUND_UP[4] = { 0, 3, 2, 1 };
-
-static inline int
-round_up(int n)
-{
- return n + ROUND_UP[n % 4];
-}
-
-static int
-read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
-{
- int bytesRead = 0;
- int amt;
- SnapshotHeader header;
-
- amt = read(fd, &header, sizeof(header));
- if (amt != sizeof(header)) {
- return errno;
- }
- bytesRead += amt;
-
- if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
- LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
- return 1;
- }
-
- for (int i=0; i<header.fileCount; i++) {
- FileState file;
- char filenameBuf[128];
-
- amt = read(fd, &file, sizeof(file));
- if (amt != sizeof(file)) {
- LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
- return 1;
- }
- bytesRead += amt;
-
- // filename is not NULL terminated, but it is padded
- int nameBufSize = round_up(file.nameLen);
- char* filename = nameBufSize <= (int)sizeof(filenameBuf)
- ? filenameBuf
- : (char*)malloc(nameBufSize);
- amt = read(fd, filename, nameBufSize);
- if (amt == nameBufSize) {
- snapshot->add(String8(filename, file.nameLen), file);
- }
- bytesRead += amt;
- if (filename != filenameBuf) {
- free(filename);
- }
- if (amt != nameBufSize) {
- LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
- return 1;
- }
- }
-
- if (header.totalSize != bytesRead) {
- LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
- header.totalSize, bytesRead);
- return 1;
- }
-
- return 0;
-}
-
-static int
-write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
-{
- int bytesWritten = sizeof(SnapshotHeader);
- // preflight size
- const int N = snapshot.size();
- for (int i=0; i<N; i++) {
- const String8& name = snapshot.keyAt(i);
- bytesWritten += sizeof(FileState) + round_up(name.length());
- }
-
- int amt;
- SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
-
- amt = write(fd, &header, sizeof(header));
- if (amt != sizeof(header)) {
- LOGW("write_snapshot_file error writing header %s", strerror(errno));
- return errno;
- }
-
- for (int i=0; i<header.fileCount; i++) {
- const String8& name = snapshot.keyAt(i);
- FileState file = snapshot.valueAt(i);
- int nameLen = file.nameLen = name.length();
-
- amt = write(fd, &file, sizeof(file));
- if (amt != sizeof(file)) {
- LOGW("write_snapshot_file error writing header %s", strerror(errno));
- return 1;
- }
-
- // filename is not NULL terminated, but it is padded
- amt = write(fd, name.string(), nameLen);
- if (amt != nameLen) {
- LOGW("write_snapshot_file error writing filename %s", strerror(errno));
- return 1;
- }
- int paddingLen = ROUND_UP[nameLen % 4];
- if (paddingLen != 0) {
- int padding = 0xabababab;
- amt = write(fd, &padding, paddingLen);
- if (amt != paddingLen) {
- LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
- paddingLen, strerror(errno));
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static int
-write_delete_file(const String8& key)
-{
- LOGP("write_delete_file %s\n", key.string());
- return 0;
-}
-
-static int
-write_update_file(const String8& realFilename, const String8& key)
-{
- LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
- return 0;
-}
-
-static int
-compute_crc32(const String8& filename)
-{
- const int bufsize = 4*1024;
- int amt;
-
- int fd = open(filename.string(), O_RDONLY);
- if (fd == -1) {
- return -1;
- }
-
- char* buf = (char*)malloc(bufsize);
- int crc = crc32(0L, Z_NULL, 0);
-
- while ((amt = read(fd, buf, bufsize)) != 0) {
- crc = crc32(crc, (Bytef*)buf, amt);
- }
-
- close(fd);
- free(buf);
-
- return crc;
-}
-
-int
-back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
- char const* fileBase, char const* const* files, int fileCount)
-{
- int err;
- const String8 base(fileBase);
- KeyedVector<String8,FileState> oldSnapshot;
- KeyedVector<String8,FileState> newSnapshot;
-
- if (oldSnapshotFD != -1) {
- err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
- if (err != 0) {
- // On an error, treat this as a full backup.
- oldSnapshot.clear();
- }
- }
-
- for (int i=0; i<fileCount; i++) {
- String8 name(files[i]);
- FileState s;
- struct stat st;
- String8 realFilename(base);
- realFilename.appendPath(name);
-
- err = stat(realFilename.string(), &st);
- if (err != 0) {
- LOGW("Error stating file %s", realFilename.string());
- continue;
- }
-
- s.modTime_sec = st.st_mtime;
- s.modTime_nsec = 0; // workaround sim breakage
- //s.modTime_nsec = st.st_mtime_nsec;
- s.size = st.st_size;
- s.crc32 = compute_crc32(realFilename);
-
- newSnapshot.add(name, s);
- }
-
- int n = 0;
- int N = oldSnapshot.size();
- int m = 0;
-
- while (n<N && m<fileCount) {
- const String8& p = oldSnapshot.keyAt(n);
- const String8& q = newSnapshot.keyAt(m);
- int cmp = p.compare(q);
- if (cmp > 0) {
- // file added
- String8 realFilename(base);
- realFilename.appendPath(q);
- write_update_file(realFilename, q);
- m++;
- }
- else if (cmp < 0) {
- // file removed
- write_delete_file(p);
- n++;
- }
- else {
- // both files exist, check them
- String8 realFilename(base);
- realFilename.appendPath(q);
- const FileState& f = oldSnapshot.valueAt(n);
- const FileState& g = newSnapshot.valueAt(m);
-
- LOGP("%s\n", q.string());
- LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
- f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
- LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
- g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
- if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
- || f.size != g.size || f.crc32 != g.crc32) {
- write_update_file(realFilename, p);
- }
- n++;
- m++;
- }
- }
-
- // these were deleted
- while (n<N) {
- write_delete_file(oldSnapshot.keyAt(n));
- n++;
- }
-
- // these were added
- while (m<fileCount) {
- const String8& q = newSnapshot.keyAt(m);
- String8 realFilename(base);
- realFilename.appendPath(q);
- write_update_file(realFilename, q);
- m++;
- }
-
- err = write_snapshot_file(newSnapshotFD, newSnapshot);
-
- return 0;
-}
-
-#if TEST_BACKUP_HELPERS
-
-#define SCRATCH_DIR "/data/backup_helper_test/"
-
-static int
-write_text_file(const char* path, const char* data)
-{
- int amt;
- int fd;
- int len;
-
- fd = creat(path, 0666);
- if (fd == -1) {
- fprintf(stderr, "creat %s failed\n", path);
- return errno;
- }
-
- len = strlen(data);
- amt = write(fd, data, len);
- if (amt != len) {
- fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
- return errno;
- }
-
- close(fd);
-
- return 0;
-}
-
-static int
-compare_file(const char* path, const unsigned char* data, int len)
-{
- int fd;
- int amt;
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
- return errno;
- }
-
- unsigned char* contents = (unsigned char*)malloc(len);
- if (contents == NULL) {
- fprintf(stderr, "malloc(%d) failed\n", len);
- return ENOMEM;
- }
-
- bool sizesMatch = true;
- amt = lseek(fd, 0, SEEK_END);
- if (amt != len) {
- fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
- sizesMatch = false;
- }
- lseek(fd, 0, SEEK_SET);
-
- int readLen = amt < len ? amt : len;
- amt = read(fd, contents, readLen);
- if (amt != readLen) {
- fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
- }
-
- bool contentsMatch = true;
- for (int i=0; i<readLen; i++) {
- if (data[i] != contents[i]) {
- if (contentsMatch) {
- fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
- contentsMatch = false;
- }
- fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
- }
- }
-
- return contentsMatch && sizesMatch ? 0 : 1;
-}
-
-int
-backup_helper_test_empty()
-{
- int err;
- int fd;
- KeyedVector<String8,FileState> snapshot;
- const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
-
- system("rm -r " SCRATCH_DIR);
- mkdir(SCRATCH_DIR, 0777);
-
- // write
- fd = creat(filename, 0666);
- if (fd == -1) {
- fprintf(stderr, "error creating %s\n", filename);
- return 1;
- }
-
- err = write_snapshot_file(fd, snapshot);
-
- close(fd);
-
- if (err != 0) {
- fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
- return err;
- }
-
- static const unsigned char correct_data[] = {
- 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
- 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
- };
-
- err = compare_file(filename, correct_data, sizeof(correct_data));
- if (err != 0) {
- return err;
- }
-
- // read
- fd = open(filename, O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "error opening for read %s\n", filename);
- return 1;
- }
-
- KeyedVector<String8,FileState> readSnapshot;
- err = read_snapshot_file(fd, &readSnapshot);
- if (err != 0) {
- fprintf(stderr, "read_snapshot_file failed %d\n", err);
- return err;
- }
-
- if (readSnapshot.size() != 0) {
- fprintf(stderr, "readSnapshot should be length 0\n");
- return 1;
- }
-
- return 0;
-}
-
-int
-backup_helper_test_four()
-{
- int err;
- int fd;
- KeyedVector<String8,FileState> snapshot;
- const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
-
- system("rm -r " SCRATCH_DIR);
- mkdir(SCRATCH_DIR, 0777);
-
- // write
- fd = creat(filename, 0666);
- if (fd == -1) {
- fprintf(stderr, "error opening %s\n", filename);
- return 1;
- }
-
- String8 filenames[4];
- FileState states[4];
-
- states[0].modTime_sec = 0xfedcba98;
- states[0].modTime_nsec = 0xdeadbeef;
- states[0].size = 0xababbcbc;
- states[0].crc32 = 0x12345678;
- states[0].nameLen = -12;
- filenames[0] = String8("bytes_of_padding");
- snapshot.add(filenames[0], states[0]);
-
- states[1].modTime_sec = 0x93400031;
- states[1].modTime_nsec = 0xdeadbeef;
- states[1].size = 0x88557766;
- states[1].crc32 = 0x22334422;
- states[1].nameLen = -1;
- filenames[1] = String8("bytes_of_padding3");
- snapshot.add(filenames[1], states[1]);
-
- states[2].modTime_sec = 0x33221144;
- states[2].modTime_nsec = 0xdeadbeef;
- states[2].size = 0x11223344;
- states[2].crc32 = 0x01122334;
- states[2].nameLen = 0;
- filenames[2] = String8("bytes_of_padding_2");
- snapshot.add(filenames[2], states[2]);
-
- states[3].modTime_sec = 0x33221144;
- states[3].modTime_nsec = 0xdeadbeef;
- states[3].size = 0x11223344;
- states[3].crc32 = 0x01122334;
- states[3].nameLen = 0;
- filenames[3] = String8("bytes_of_padding__1");
- snapshot.add(filenames[3], states[3]);
-
- err = write_snapshot_file(fd, snapshot);
-
- close(fd);
-
- if (err != 0) {
- fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
- return err;
- }
-
- static const unsigned char correct_data[] = {
- // header
- 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
- 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00,
-
- // bytes_of_padding
- 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
- 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12,
- 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
- 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
- 0x64, 0x69, 0x6e, 0x67,
-
- // bytes_of_padding3
- 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
- 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22,
- 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
- 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
- 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab,
-
- // bytes of padding2
- 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
- 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
- 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
- 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
- 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab,
-
- // bytes of padding3
- 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
- 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
- 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
- 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
- 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab
- };
-
- err = compare_file(filename, correct_data, sizeof(correct_data));
- if (err != 0) {
- return err;
- }
-
- // read
- fd = open(filename, O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "error opening for read %s\n", filename);
- return 1;
- }
-
-
- KeyedVector<String8,FileState> readSnapshot;
- err = read_snapshot_file(fd, &readSnapshot);
- if (err != 0) {
- fprintf(stderr, "read_snapshot_file failed %d\n", err);
- return err;
- }
-
- if (readSnapshot.size() != 4) {
- fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
- return 1;
- }
-
- bool matched = true;
- for (size_t i=0; i<readSnapshot.size(); i++) {
- const String8& name = readSnapshot.keyAt(i);
- const FileState state = readSnapshot.valueAt(i);
-
- if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
- || states[i].modTime_nsec != state.modTime_nsec
- || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
- fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
- " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
- states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
- name.length(), filenames[i].string(),
- state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
- name.string());
- matched = false;
- }
- }
-
- return matched ? 0 : 1;
-}
-
-static int
-get_mod_time(const char* filename, struct timeval times[2])
-{
- int err;
- struct stat64 st;
- err = stat64(filename, &st);
- if (err != 0) {
- fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
- return errno;
- }
- times[0].tv_sec = st.st_atime;
- times[0].tv_usec = st.st_atime_nsec / 1000;
- times[1].tv_sec = st.st_mtime;
- times[1].tv_usec = st.st_mtime_nsec / 1000;
- return 0;
-}
-
-int
-backup_helper_test_files()
-{
- int err;
- int newSnapshotFD;
- int oldSnapshotFD;
-
- system("rm -r " SCRATCH_DIR);
- mkdir(SCRATCH_DIR, 0777);
- mkdir(SCRATCH_DIR "data", 0777);
-
- write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
- write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
- write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
- write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
- write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
- write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
-
- char const* files_before[] = {
- "data/b",
- "data/c",
- "data/d",
- "data/e",
- "data/f"
- };
-
- newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
- if (newSnapshotFD == -1) {
- fprintf(stderr, "error creating: %s\n", strerror(errno));
- return errno;
- }
-
- err = back_up_files(-1, newSnapshotFD, 0, SCRATCH_DIR, files_before, 5);
- if (err != 0) {
- return err;
- }
-
- close(newSnapshotFD);
-
- sleep(3);
-
- struct timeval d_times[2];
- struct timeval e_times[2];
-
- err = get_mod_time(SCRATCH_DIR "data/d", d_times);
- err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
- if (err != 0) {
- return err;
- }
-
- write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
- unlink(SCRATCH_DIR "data/c");
- write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
- write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
- utimes(SCRATCH_DIR "data/d", d_times);
- write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
- utimes(SCRATCH_DIR "data/e", e_times);
- write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
- unlink(SCRATCH_DIR "data/f");
-
- char const* files_after[] = {
- "data/a", // added
- "data/b", // same
- "data/c", // different mod time
- "data/d", // different size (same mod time)
- "data/e", // different contents (same mod time, same size)
- "data/g" // added
- };
-
- oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
- if (oldSnapshotFD == -1) {
- fprintf(stderr, "error opening: %s\n", strerror(errno));
- return errno;
- }
-
- newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
- if (newSnapshotFD == -1) {
- fprintf(stderr, "error creating: %s\n", strerror(errno));
- return errno;
- }
-
- err = back_up_files(oldSnapshotFD, newSnapshotFD, 0, SCRATCH_DIR, files_after, 6);
- if (err != 0) {
- return err;
- }
-
- close(oldSnapshotFD);
- close(newSnapshotFD);
-
- return 0;
-}
-
-#endif // TEST_BACKUP_HELPERS
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
index ba19520..ab48c69 100644
--- a/libs/utils/futex_synchro.c
+++ b/libs/utils/futex_synchro.c
@@ -28,6 +28,7 @@
// This futex glue code is need on desktop linux, but is already part of bionic.
#if !defined(HAVE_FUTEX_WRAPPERS)
+#include <unistd.h>
#include <sys/syscall.h>
typedef unsigned int u32;
#define asmlinkage
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 8fa7566..3e9c6a5 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -951,6 +951,8 @@
v->index = first;
first &= vertex_cache_t::INDEX_MASK;
const GLubyte* vp = c->arrays.vertex.element(first);
+ v->obj.z = 0;
+ v->obj.w = 0x10000;
c->arrays.vertex.fetch(c, v->obj.v, vp);
c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
c->arrays.perspective(c, v);
@@ -966,6 +968,8 @@
do {
v->flags = 0;
v->index = first++;
+ v->obj.z = 0;
+ v->obj.w = 0x10000;
c->arrays.vertex.fetch(c, v->obj.v, vp);
c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
c->arrays.perspective(c, v);
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index 25c41d0..8ae32cc 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -38,13 +38,14 @@
static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
-static inline void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b);
static __attribute__((noinline))
void vnorm3(GLfixed* d, const GLfixed* a);
static inline void vsa3(GLfixed* d,
const GLfixed* m, GLfixed s, const GLfixed* a);
+static inline void vss3(GLfixed* d,
+ const GLfixed* m, GLfixed s, const GLfixed* a);
static inline void vmla3(GLfixed* d,
const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
static inline void vmul3(GLfixed* d,
@@ -151,18 +152,10 @@
}
static inline
-void vsub3w(GLfixed* d, const GLfixed* a, const GLfixed* b) {
- const GLfixed wa = a[3];
- const GLfixed wb = b[3];
- if (ggl_likely(wa == wb)) {
- d[0] = a[0] - b[0];
- d[1] = a[1] - b[1];
- d[2] = a[2] - b[2];
- } else {
- d[0] = gglMulSubx(a[0], wb, gglMulx(b[0], wa));
- d[1] = gglMulSubx(a[1], wb, gglMulx(b[1], wa));
- d[2] = gglMulSubx(a[2], wb, gglMulx(b[2], wa));
- }
+void vss3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
+ d[0] = gglMulSubx(m[0], s, a[0]);
+ d[1] = gglMulSubx(m[1], s, a[1]);
+ d[2] = gglMulSubx(m[2], s, a[2]);
}
static inline
@@ -227,7 +220,7 @@
const int i = 31 - gglClz(en);
en &= ~(1<<i);
light_t& l = c->lighting.lights[i];
- c->transforms.mvui.point3(&c->transforms.mvui,
+ c->transforms.mvui.point4(&c->transforms.mvui,
&l.objPosition, &l.position);
vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
}
@@ -318,6 +311,11 @@
vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
+ // this is just a flag to tell if we have a specular component
+ l.implicitSpecular.v[3] =
+ l.implicitSpecular.r |
+ l.implicitSpecular.g |
+ l.implicitSpecular.b;
}
// emission and ambient for the whole scene
vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
@@ -343,7 +341,11 @@
vec4_t n;
c->arrays.normal.fetch(c, n.v,
c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK));
- if (c->transforms.rescaleNormals == GL_NORMALIZE)
+
+ // TODO: right now we handle GL_RESCALE_NORMALS as if ti were
+ // GL_NORMALIZE. We could optimize this by scaling mvui
+ // appropriately instead.
+ if (c->transforms.rescaleNormals)
vnorm3(n.v, n.v);
const material_t& material = c->lighting.front;
@@ -360,7 +362,8 @@
// compute vertex-to-light vector
if (ggl_unlikely(l.position.w)) {
- vsub3w(d.v, l.objPosition.v, v->obj.v);
+ // lightPos/1.0 - vertex/vertex.w == lightPos*vertex.w - vertex
+ vss3(d.v, l.objPosition.v, v->obj.w, v->obj.v);
sqDist = dot3(d.v, d.v);
vscale3(d.v, d.v, gglSqrtRecipx(sqDist));
} else {
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index f175cda..0b68dc0 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -55,7 +55,7 @@
static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
-static void normal__generic(transform_t const*, vec4_t* c, vec4_t const* o);
+static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o);
// ----------------------------------------------------------------------------
#if 0
@@ -209,7 +209,8 @@
{
flags = 0;
ops = OP_ALL;
- point3 = normal__generic;
+ point3 = point4__mvui;
+ point4 = point4__mvui;
}
void transform_t::dump(const char* what)
@@ -596,66 +597,19 @@
void transform_state_t::update_mvui()
{
+ GLfloat r[16];
const GLfloat* const mv = modelview.top().elements();
-
- /*
- When transforming normals, we can use the upper 3x3 matrix, see:
- http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html
- */
- // Also note that:
- // l(obj) = tr(M).l(eye) for infinite light
- // l(obj) = inv(M).l(eye) for local light
-
- const uint32_t ops = modelview.top_ops() & ~OP_TRANSLATE;
- if (ggl_likely((!(ops & ~OP_ROTATE)) ||
- (rescaleNormals && modelview.isRigidBody()))) {
- // if the modelview matrix is a rigid body transformation
- // (translation, rotation, uniform scaling), then we can bypass
- // the inverse by transposing the matrix.
- GLfloat rescale = 1.0f;
- if (rescaleNormals == GL_RESCALE_NORMAL) {
- if (!(ops & ~OP_UNIFORM_SCALE)) {
- rescale = reciprocalf(mv[I(0,0)]);
- } else {
- rescale = rsqrtf(
- sqrf(mv[I(2,0)]) + sqrf(mv[I(2,1)]) + sqrf(mv[I(2,2)]));
- }
- }
- GLfixed* const x = mvui.matrix.m;
- for (int i=0 ; i<3 ; i++) {
- x[I(i,0)] = gglFloatToFixed(mv[I(0,i)] * rescale);
- x[I(i,1)] = gglFloatToFixed(mv[I(1,i)] * rescale);
- x[I(i,2)] = gglFloatToFixed(mv[I(2,i)] * rescale);
- }
- mvui.picker();
- return;
- }
-
- GLfloat r[3][3];
- r[0][0] = det22(mv[I(1,1)], mv[I(2,1)], mv[I(1,2)], mv[I(2,2)]);
- r[0][1] =ndet22(mv[I(0,1)], mv[I(2,1)], mv[I(0,2)], mv[I(2,2)]);
- r[0][2] = det22(mv[I(0,1)], mv[I(1,1)], mv[I(0,2)], mv[I(1,2)]);
- r[1][0] =ndet22(mv[I(1,0)], mv[I(2,0)], mv[I(1,2)], mv[I(2,2)]);
- r[1][1] = det22(mv[I(0,0)], mv[I(2,0)], mv[I(0,2)], mv[I(2,2)]);
- r[1][2] =ndet22(mv[I(0,0)], mv[I(1,0)], mv[I(0,2)], mv[I(1,2)]);
- r[2][0] = det22(mv[I(1,0)], mv[I(2,0)], mv[I(1,1)], mv[I(2,1)]);
- r[2][1] =ndet22(mv[I(0,0)], mv[I(2,0)], mv[I(0,1)], mv[I(2,1)]);
- r[2][2] = det22(mv[I(0,0)], mv[I(1,0)], mv[I(0,1)], mv[I(1,1)]);
-
- GLfloat rdet;
- if (rescaleNormals == GL_RESCALE_NORMAL) {
- rdet = rsqrtf(sqrf(r[0][2]) + sqrf(r[1][2]) + sqrf(r[2][2]));
- } else {
- rdet = reciprocalf(
- r[0][0]*mv[I(0,0)] + r[0][1]*mv[I(1,0)] + r[0][2]*mv[I(2,0)]);
- }
+ // TODO: we need a faster invert, especially for when the modelview
+ // is a rigid-body matrix
+ invert(r, mv);
GLfixed* const x = mvui.matrix.m;
- for (int i=0 ; i<3 ; i++) {
- x[I(i,0)] = gglFloatToFixed(r[i][0] * rdet);
- x[I(i,1)] = gglFloatToFixed(r[i][1] * rdet);
- x[I(i,2)] = gglFloatToFixed(r[i][2] * rdet);
+ for (int i=0 ; i<4 ; i++) {
+ x[I(i,0)] = gglFloatToFixed(r[I(i,0)]);
+ x[I(i,1)] = gglFloatToFixed(r[I(i,1)]);
+ x[I(i,2)] = gglFloatToFixed(r[I(i,2)]);
+ x[I(i,4)] = gglFloatToFixed(r[I(i,3)]);
}
mvui.picker();
}
@@ -783,14 +737,19 @@
lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]);
}
-void normal__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
+ // this used for transforming light positions back to object space.
+ // Lights have 3 components positions, so w is always 1.
+ // however, it is used as a switch for directional lights, so we need
+ // to preserve it.
const GLfixed* const m = mx->matrix.m;
const GLfixed rx = rhs->x;
const GLfixed ry = rhs->y;
const GLfixed rz = rhs->z;
- lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]);
- lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]);
- lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]);
+ lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
+ lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
+ lhs->w = rhs->w;
}
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index b6f534b..14a910c 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -900,7 +900,7 @@
memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
break;
default:
- ogles_error(c, GL_INVALID_ENUM);
+ texParameterx(target, pname, GLfixed(params[0]), c);
return;
}
}
@@ -919,6 +919,13 @@
texParameterx(target, pname, param, c);
}
+void glTexParameteri(
+ GLenum target, GLenum pname, GLint param)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ texParameterx(target, pname, GLfixed(param), c);
+}
+
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 5ba6b76..23304d5 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -39,7 +39,7 @@
GLES_CM/gl.cpp.arm \
#
-LOCAL_SHARED_LIBRARIES += libcutils libutils libui libEGL
+LOCAL_SHARED_LIBRARIES += libcutils libEGL
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libGLESv1_CM
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 25e31ee..de323b3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1052,23 +1052,25 @@
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
+ EGLSurface impl_draw = EGL_NO_SURFACE;
+ EGLSurface impl_read = EGL_NO_SURFACE;
egl_context_t * const c = get_context(ctx);
if (draw != EGL_NO_SURFACE) {
egl_surface_t const * d = get_surface(draw);
if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (d->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
- draw = d->surface;
+ impl_draw = d->surface;
}
if (read != EGL_NO_SURFACE) {
egl_surface_t const * r = get_surface(read);
if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (r->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
- read = r->surface;
+ impl_read = r->surface;
}
EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
- dp->dpys[c->impl], draw, read, c->context);
+ dp->dpys[c->impl], impl_draw, impl_read, c->context);
if (result == EGL_TRUE) {
setGlThreadSpecific(c->cnx->hooks);
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
index f9dc5f1..4c902c8 100644
--- a/opengl/libs/EGL/gpu.cpp
+++ b/opengl/libs/EGL/gpu.cpp
@@ -118,6 +118,11 @@
return 0;
}
+ if (info.regs == 0) {
+ LOGD("requestGPU() failed");
+ return 0;
+ }
+
bool failed = false;
request_gpu_t* gpu = &gRegions;
memset(gpu, 0, sizeof(*gpu));
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index 46958d3..e193483 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -5,7 +5,7 @@
LOCAL_SRC_FILES:= app-linux.c demo.c.arm
LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
LOCAL_MODULE:= angeles
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
@@ -13,5 +13,5 @@
LOCAL_SRC_FILES:= gpustate.c
LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM
LOCAL_MODULE:= gpustate
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index a448f0d..31b7d9a 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -12,6 +12,6 @@
LOCAL_MODULE:= test-opengl-filter
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 26836c1..8b46cd7 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -12,6 +12,6 @@
LOCAL_MODULE:= test-opengl-finish
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/lighting1709/Android.mk b/opengl/tests/lighting1709/Android.mk
new file mode 100644
index 0000000..9563e61
--- /dev/null
+++ b/opengl/tests/lighting1709/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := LightingTest
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/opengl/tests/lighting1709/AndroidManifest.xml b/opengl/tests/lighting1709/AndroidManifest.xml
new file mode 100644
index 0000000..6c23d42
--- /dev/null
+++ b/opengl/tests/lighting1709/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.lightingtest">
+
+ <application>
+ <activity android:name="ClearActivity" android:label="LightingTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java b/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java
new file mode 100644
index 0000000..3ae8c5c
--- /dev/null
+++ b/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.lightingtest;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.app.Activity;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.MotionEvent;
+
+public class ClearActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mGLView = new ClearGLSurfaceView(this);
+ setContentView(mGLView);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mGLView.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mGLView.onResume();
+ }
+ private GLSurfaceView mGLView;
+}
+
+class ClearGLSurfaceView extends GLSurfaceView {
+ public ClearGLSurfaceView(Context context) {
+ super(context);
+ mRenderer = new ClearRenderer();
+ setRenderer(mRenderer);
+ }
+
+ ClearRenderer mRenderer;
+}
+
+class ClearRenderer implements GLSurfaceView.Renderer {
+ public ClearRenderer() {
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing special.
+ }
+
+ public void onSurfaceChanged(GL10 gl, int w, int h) {
+ // Compute the projection matrix
+ gl.glMatrixMode(GL10.GL_PROJECTION);
+ gl.glLoadIdentity();
+
+ // Compute the boundaries of the frustum
+ float fl = (float) (-(w / 2)) / 288;
+ float fr = (float) (w / 2) / 288;
+ float ft = (float) (h / 2) / 288;
+ float fb = (float) (-(h / 2)) / 288;
+
+ // Set the view frustum
+ gl.glFrustumf(fl, fr, fb, ft, 1.0f, 2000.0f);
+
+ // Set the viewport dimensions
+ gl.glMatrixMode(GL10.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ gl.glViewport(0, 0, w, h);
+ }
+
+ public void onDrawFrame(GL10 gl) {
+ gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+
+ final float lightOff[] = {0.0f, 0.0f, 0.0f, 1.0f};
+ final float lightAmbient[] = {5.0f, 0.0f, 0.0f, 1.0f};
+ final float lightDiffuse[] = {0.0f, 2.0f, 0.0f, 0.0f};
+ final float lightPosSpot[] = {0.0f, 0.0f, -8.0f, 1.0f};
+
+ final float pos[] = {
+ -5.0f, -1.5f, 0.0f,
+ 0.0f, -1.5f, 0.0f,
+ 5.0f, -1.5f, 0.0f,
+ };
+
+ final float v[] = new float[9];
+ ByteBuffer vbb = ByteBuffer.allocateDirect(v.length*4);
+ vbb.order(ByteOrder.nativeOrder());
+ FloatBuffer vb = vbb.asFloatBuffer();
+
+ gl.glDisable(GL10.GL_DITHER);
+
+ gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient, 0);
+ gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse, 0);
+ gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, lightOff, 0);
+ gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPosSpot, 0);
+ gl.glEnable(GL10.GL_LIGHT0);
+
+ gl.glEnable(GL10.GL_LIGHTING);
+
+
+ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+ gl.glNormal3f(0, 0, 1);
+
+
+ // draw first 3 triangles, without using transforms
+ for (int i=0 ; i<3 ; i++) {
+ v[0] = -1; v[1] =-1; v[2] = -10;
+ v[3] = 0; v[4] = 1; v[5] = -10;
+ v[6] = 1; v[7] =-1; v[8] = -10;
+ for (int j=0 ; j<3 ; j++) {
+ v[j*3+0] -= pos[i*3+0];
+ v[j*3+1] -= pos[i*3+1];
+ v[j*3+2] -= pos[i*3+2];
+ }
+ vb.put(v).position(0);
+ gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+ gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+ }
+
+ // draw the 2nd batch this time with transforms
+ v[0] = -1; v[1] =-1; v[2] = -10;
+ v[3] = 0; v[4] = 1; v[5] = -10;
+ v[6] = 1; v[7] =-1; v[8] = -10;
+ vb.put(v).position(0);
+ gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vb);
+
+ // draw lower left triangle
+ gl.glPushMatrix();
+ gl.glTranslatef(pos[0], pos[1], pos[2]);
+ gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+ gl.glPopMatrix();
+
+ // draw lower middle triangle
+ gl.glPushMatrix();
+ gl.glTranslatef(pos[3], pos[4], pos[5]);
+ gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+ gl.glPopMatrix();
+
+ // draw lower right triangle
+ gl.glPushMatrix();
+ gl.glTranslatef(pos[6], pos[7], pos[8]);
+ gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
+ gl.glPopMatrix();
+ }
+
+ public int[] getConfigSpec() {
+ int[] configSpec = { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
+ return configSpec;
+ }
+}
+
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index a8c6220..8d5f56d 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -12,6 +12,6 @@
LOCAL_MODULE:= test-opengl-textures
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 5cd1f04..76fd8dd 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -12,6 +12,6 @@
LOCAL_MODULE:= test-opengl-tritex
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 011a6ed..9bff0b2 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -4,14 +4,31 @@
rm -rf out generated
mkdir out
+
+# Create dummy Java files for Android APIs that are used by the code we generate.
+# This allows us to test the generated code without building the rest of Android.
+
mkdir -p out/javax/microedition/khronos/opengles
mkdir -p out/com/google/android/gles_jni
+mkdir -p out/android/app
mkdir -p out/android/graphics
mkdir -p out/android/opengl
+mkdir -p out/android/content
+mkdir -p out/android/content/pm
+mkdir -p out/android/os
+mkdir -p out/android/util
echo "package android.graphics;" > out/android/graphics/Canvas.java
echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
+echo "package android.app; import android.content.pm.IPackageManager; public class ActivityThread { public static final ActivityThread currentActivityThread() { return null; } public static final String currentPackageName(){ return null; } public static IPackageManager getPackageManager() { return null;} }" > out/android/app/ActivityThread.java
+# echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
+echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
+echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
+echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;}; }" > out/android/os/Build.java
+echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java
+echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java
+
GLFILE=out/javax/microedition/khronos/opengles/GL.java
cp stubs/jsr239/GLHeader.java-if $GLFILE
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index b0997b1..7340357 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -890,16 +890,10 @@
cname +
" = (" +
cfunc.getArgType(cIndex).getDeclaration() +
- ") _env->GetDirectBufferAddress(" +
- (mUseCPlusPlus ? "" : "_env, ") +
+ ") getDirectBufferPointer(_env, " +
cname + "_buf);");
String iii = " ";
- out.println(iii + indent + "if ( ! " + cname + " ) {");
- out.println(iii + iii + indent +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, \"Must use a native order direct Buffer\");");
+ out.println(iii + indent + "if ( ! " + cname + " ) {");
out.println(iii + iii + indent + "return;");
out.println(iii + indent + "}");
} else {
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index 3948fd3..e1c09f4 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -132,6 +132,19 @@
commit ? 0 : JNI_ABORT);
}
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+ char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+ if (buf) {
+ jint position = _env->GetIntField(buffer, positionID);
+ jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ buf += position << elementSizeShift;
+ } else {
+ _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ }
+ return (void*) buf;
+}
+
static int
getNumCompressedTextureFormats() {
int numCompressedTextureFormats = 0;
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 11c6087..4494643 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -44,9 +44,11 @@
static jclass UOEClass;
static jclass IAEClass;
static jclass AIOOBEClass;
+static jclass G11ImplClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
+static jmethodID allowIndirectBuffersID;
static jfieldID positionID;
static jfieldID limitID;
static jfieldID elementSizeShiftID;
@@ -62,13 +64,17 @@
jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+ jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl");
+ G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal);
+
getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
"getBasePointer", "(Ljava/nio/Buffer;)J");
getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
"getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
"getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
-
+ allowIndirectBuffersID = _env->GetStaticMethodID(g11impClassLocal,
+ "allowIndirectBuffers", "(Ljava/lang/String;)Z");
positionID = _env->GetFieldID(bufferClass, "position", "I");
limitID = _env->GetFieldID(bufferClass, "limit", "I");
elementSizeShiftID =
@@ -118,6 +124,9 @@
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
+ if (*array == NULL) {
+ return (void*) NULL;
+ }
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
@@ -132,6 +141,45 @@
commit ? 0 : JNI_ABORT);
}
+extern "C" {
+extern char* __progname;
+}
+
+static bool
+allowIndirectBuffers(JNIEnv *_env) {
+ static jint sIndirectBufferCompatability;
+ if (sIndirectBufferCompatability == 0) {
+ jobject appName = _env->NewStringUTF(::__progname);
+ sIndirectBufferCompatability = _env->CallStaticBooleanMethod(G11ImplClass, allowIndirectBuffersID, appName) ? 2 : 1;
+ }
+ return sIndirectBufferCompatability == 2;
+}
+
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+ if (!buffer) {
+ return NULL;
+ }
+ void* buf = _env->GetDirectBufferAddress(buffer);
+ if (buf) {
+ jint position = _env->GetIntField(buffer, positionID);
+ jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ buf = ((char*) buf) + (position << elementSizeShift);
+ } else {
+ if (allowIndirectBuffers(_env)) {
+ jarray array = 0;
+ jint remaining;
+ buf = getPointer(_env, buffer, &array, &remaining);
+ if (array) {
+ releasePointer(_env, array, buf, 0);
+ }
+ } else {
+ _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ }
+ }
+ return buf;
+}
+
static int
getNumCompressedTextureFormats() {
int numCompressedTextureFormats = 0;
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index db3a41c..fe60c5d 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -18,6 +18,12 @@
package com.google.android.gles_jni;
+import android.app.ActivityThread;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.os.Build;
+import android.util.Log;
+
import java.nio.Buffer;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL10Ext;
@@ -42,7 +48,28 @@
public GLImpl() {
}
- public void glGetPointerv(int pname, java.nio.Buffer[] params) {
- throw new UnsupportedOperationException("glGetPointerv");
- }
+ public void glGetPointerv(int pname, java.nio.Buffer[] params) {
+ throw new UnsupportedOperationException("glGetPointerv");
+ }
+
+ private static boolean allowIndirectBuffers(String appName) {
+ boolean result = false;
+ int version = 0;
+ IPackageManager pm = ActivityThread.getPackageManager();
+ try {
+ ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);
+ if (applicationInfo != null) {
+ version = applicationInfo.targetSdkVersion;
+ }
+ } catch (android.os.RemoteException e) {
+ // ignore
+ }
+ Log.e("OpenGLES", String.format(
+ "Application %s (SDK target %d) called a GL11 Pointer method with an indirect Buffer.",
+ appName, version));
+ if (version <= Build.VERSION_CODES.CUPCAKE) {
+ result = true;
+ }
+ return result;
+ }
diff --git a/vpn/java/android/net/vpn/IVpnService.aidl b/vpn/java/android/net/vpn/IVpnService.aidl
new file mode 100644
index 0000000..fedccb0
--- /dev/null
+++ b/vpn/java/android/net/vpn/IVpnService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.net.vpn.VpnProfile;
+
+/**
+ * Interface to access a VPN service.
+ * {@hide}
+ */
+interface IVpnService {
+ /**
+ * Sets up the VPN connection.
+ * @param profile the profile object
+ * @param username the username for authentication
+ * @param password the corresponding password for authentication
+ */
+ boolean connect(in VpnProfile profile, String username, String password);
+
+ /**
+ * Tears down the VPN connection.
+ */
+ void disconnect();
+
+ /**
+ * Makes the service broadcast the connectivity state.
+ */
+ void checkStatus(in VpnProfile profile);
+}
diff --git a/vpn/java/android/net/vpn/L2tpIpsecProfile.java b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
new file mode 100644
index 0000000..4ae2dec
--- /dev/null
+++ b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for certificate-based L2TP-over-IPSec type of VPN.
+ * {@hide}
+ */
+public class L2tpIpsecProfile extends L2tpProfile {
+ private static final long serialVersionUID = 1L;
+
+ private String mUserCertificate;
+ private String mCaCertificate;
+
+ @Override
+ public VpnType getType() {
+ return VpnType.L2TP_IPSEC;
+ }
+
+ public void setCaCertificate(String name) {
+ mCaCertificate = name;
+ }
+
+ public String getCaCertificate() {
+ return mCaCertificate;
+ }
+
+ public void setUserCertificate(String name) {
+ mUserCertificate = name;
+ }
+
+ public String getUserCertificate() {
+ return mUserCertificate;
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ super.readFromParcel(in);
+ mCaCertificate = in.readString();
+ mUserCertificate = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ super.writeToParcel(parcel, flags);
+ parcel.writeString(mCaCertificate);
+ parcel.writeString(mUserCertificate);
+ }
+}
diff --git a/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java
new file mode 100644
index 0000000..7a03018
--- /dev/null
+++ b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for pre-shared-key-based L2TP-over-IPSec type of VPN.
+ * {@hide}
+ */
+public class L2tpIpsecPskProfile extends L2tpProfile {
+ private static final long serialVersionUID = 1L;
+
+ private String mPresharedKey;
+
+ @Override
+ public VpnType getType() {
+ return VpnType.L2TP_IPSEC_PSK;
+ }
+
+ public void setPresharedKey(String key) {
+ mPresharedKey = key;
+ }
+
+ public String getPresharedKey() {
+ return mPresharedKey;
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ super.readFromParcel(in);
+ mPresharedKey = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ super.writeToParcel(parcel, flags);
+ parcel.writeString(mPresharedKey);
+ }
+}
diff --git a/vpn/java/android/net/vpn/L2tpProfile.java b/vpn/java/android/net/vpn/L2tpProfile.java
new file mode 100644
index 0000000..dbba0c5
--- /dev/null
+++ b/vpn/java/android/net/vpn/L2tpProfile.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for L2TP type of VPN.
+ * {@hide}
+ */
+public class L2tpProfile extends VpnProfile {
+ private static final long serialVersionUID = 1L;
+
+ private boolean mSecret;
+ private String mSecretString;
+
+ @Override
+ public VpnType getType() {
+ return VpnType.L2TP;
+ }
+
+ /**
+ * Enables/disables the secret for authenticating tunnel connection.
+ */
+ public void setSecretEnabled(boolean enabled) {
+ mSecret = enabled;
+ }
+
+ public boolean isSecretEnabled() {
+ return mSecret;
+ }
+
+ public void setSecretString(String secret) {
+ mSecretString = secret;
+ }
+
+ public String getSecretString() {
+ return mSecretString;
+ }
+
+ @Override
+ protected void readFromParcel(Parcel in) {
+ super.readFromParcel(in);
+ mSecret = in.readInt() > 0;
+ mSecretString = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ super.writeToParcel(parcel, flags);
+ parcel.writeInt(mSecret ? 1 : 0);
+ parcel.writeString(mSecretString);
+ }
+}
diff --git a/vpn/java/android/net/vpn/PptpProfile.java b/vpn/java/android/net/vpn/PptpProfile.java
new file mode 100644
index 0000000..c68bb71
--- /dev/null
+++ b/vpn/java/android/net/vpn/PptpProfile.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+/**
+ * The profile for PPTP type of VPN.
+ * {@hide}
+ */
+public class PptpProfile extends VpnProfile {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public VpnType getType() {
+ return VpnType.PPTP;
+ }
+}
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
new file mode 100644
index 0000000..dc70b26
--- /dev/null
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.util.Log;
+
+/**
+ * The class provides interface to manage all VPN-related tasks, including:
+ * <ul>
+ * <li>The list of supported VPN types.
+ * <li>API's to start/stop the service of a particular type.
+ * <li>API's to start the settings activity.
+ * <li>API's to create a profile.
+ * <li>API's to register/unregister a connectivity receiver and the keys to
+ * access the fields in a connectivity broadcast event.
+ * </ul>
+ * {@hide}
+ */
+public class VpnManager {
+ // Action for broadcasting a connectivity state.
+ private static final String ACTION_VPN_CONNECTIVITY = "vpn.connectivity";
+ /** Key to the profile name of a connectivity broadcast event. */
+ public static final String BROADCAST_PROFILE_NAME = "profile_name";
+ /** Key to the connectivity state of a connectivity broadcast event. */
+ public static final String BROADCAST_CONNECTION_STATE = "connection_state";
+
+ public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
+
+ private static final String PACKAGE_PREFIX =
+ VpnManager.class.getPackage().getName() + ".";
+
+ // Action to start VPN service
+ private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE";
+
+ // Action to start VPN settings
+ private static final String ACTION_VPN_SETTINGS = PACKAGE_PREFIX + "SETTINGS";
+
+ private static final String TAG = VpnManager.class.getSimpleName();
+
+ /**
+ * Returns all supported VPN types.
+ */
+ public static VpnType[] getSupportedVpnTypes() {
+ return VpnType.values();
+ }
+
+ private Context mContext;
+
+ /**
+ * Creates a manager object with the specified context.
+ */
+ public VpnManager(Context c) {
+ mContext = c;
+ }
+
+ /**
+ * Creates a VPN profile of the specified type.
+ *
+ * @param type the VPN type
+ * @return the profile object
+ */
+ public VpnProfile createVpnProfile(VpnType type) {
+ return createVpnProfile(type, false);
+ }
+
+ /**
+ * Creates a VPN profile of the specified type.
+ *
+ * @param type the VPN type
+ * @param customized true if the profile is custom made
+ * @return the profile object
+ */
+ public VpnProfile createVpnProfile(VpnType type, boolean customized) {
+ try {
+ VpnProfile p = (VpnProfile) type.getProfileClass().newInstance();
+ p.setCustomized(customized);
+ return p;
+ } catch (InstantiationException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Starts the VPN service to establish VPN connection.
+ */
+ public void startVpnService() {
+ mContext.startService(new Intent(ACTION_VPN_SERVICE));
+ }
+
+ /**
+ * Stops the VPN service.
+ */
+ public void stopVpnService() {
+ mContext.stopService(new Intent(ACTION_VPN_SERVICE));
+ }
+
+ /**
+ * Binds the specified ServiceConnection with the VPN service.
+ */
+ public boolean bindVpnService(ServiceConnection c) {
+ if (!mContext.bindService(new Intent(ACTION_VPN_SERVICE), c, 0)) {
+ Log.w(TAG, "failed to connect to VPN service");
+ return false;
+ } else {
+ Log.d(TAG, "succeeded to connect to VPN service");
+ return true;
+ }
+ }
+
+ /** Broadcasts the connectivity state of the specified profile. */
+ public void broadcastConnectivity(String profileName, VpnState s) {
+ Intent intent = new Intent(ACTION_VPN_CONNECTIVITY);
+ intent.putExtra(BROADCAST_PROFILE_NAME, profileName);
+ intent.putExtra(BROADCAST_CONNECTION_STATE, s);
+ mContext.sendBroadcast(intent);
+ }
+
+ public void registerConnectivityReceiver(BroadcastReceiver r) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(VpnManager.ACTION_VPN_CONNECTIVITY);
+ mContext.registerReceiver(r, filter);
+ }
+
+ public void unregisterConnectivityReceiver(BroadcastReceiver r) {
+ mContext.unregisterReceiver(r);
+ }
+
+ /** Starts the VPN settings activity. */
+ public void startSettingsActivity() {
+ Intent intent = new Intent(ACTION_VPN_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+
+ /** Creates an intent to start the VPN settings activity. */
+ public Intent createSettingsActivityIntent() {
+ Intent intent = new Intent(ACTION_VPN_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+}
diff --git a/vpn/java/android/net/vpn/VpnProfile.aidl b/vpn/java/android/net/vpn/VpnProfile.aidl
new file mode 100644
index 0000000..edeaef0
--- /dev/null
+++ b/vpn/java/android/net/vpn/VpnProfile.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+parcelable VpnProfile;
diff --git a/vpn/java/android/net/vpn/VpnProfile.java b/vpn/java/android/net/vpn/VpnProfile.java
new file mode 100644
index 0000000..bd6c809
--- /dev/null
+++ b/vpn/java/android/net/vpn/VpnProfile.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * A VPN profile.
+ * {@hide}
+ */
+public abstract class VpnProfile implements Parcelable, Serializable {
+ private static final long serialVersionUID = 1L;
+ private String mName; // unique display name
+ private String mId; // unique identifier
+ private String mServerName; // VPN server name
+ private String mDomainSuffices; // space separated list
+ private String mRouteList; // space separated list
+ private String mSavedUsername;
+ private boolean mIsCustomized;
+ private transient VpnState mState = VpnState.IDLE;
+
+ /** Sets a user-friendly name for this profile. */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Sets an ID for this profile. The caller should make sure the
+ * uniqueness of the ID.
+ */
+ public void setId(String id) {
+ mId = id;
+ }
+
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Sets the name of the VPN server. Used for DNS lookup.
+ */
+ public void setServerName(String name) {
+ mServerName = name;
+ }
+
+ public String getServerName() {
+ return mServerName;
+ }
+
+ /**
+ * Sets the domain suffices for DNS resolution.
+ *
+ * @param entries a comma-separated list of domain suffices
+ */
+ public void setDomainSuffices(String entries) {
+ mDomainSuffices = entries;
+ }
+
+ public String getDomainSuffices() {
+ return mDomainSuffices;
+ }
+
+ /**
+ * Sets the routing info for this VPN connection.
+ *
+ * @param entries a comma-separated list of routes; each entry is in the
+ * format of "(network address)/(network mask)"
+ */
+ public void setRouteList(String entries) {
+ mRouteList = entries;
+ }
+
+ public String getRouteList() {
+ return mRouteList;
+ }
+
+ public void setSavedUsername(String name) {
+ mSavedUsername = name;
+ }
+
+ public String getSavedUsername() {
+ return mSavedUsername;
+ }
+
+ public void setState(VpnState state) {
+ mState = state;
+ }
+
+ public VpnState getState() {
+ return ((mState == null) ? VpnState.IDLE : mState);
+ }
+
+ public boolean isIdle() {
+ return (mState == VpnState.IDLE);
+ }
+
+ /**
+ * Returns whether this profile is custom made (as opposed to being
+ * created by provided user interface).
+ */
+ public boolean isCustomized() {
+ return mIsCustomized;
+ }
+
+ /**
+ * Returns the VPN type of the profile.
+ */
+ public abstract VpnType getType();
+
+ void setCustomized(boolean customized) {
+ mIsCustomized = customized;
+ }
+
+ protected void readFromParcel(Parcel in) {
+ mName = in.readString();
+ mId = in.readString();
+ mServerName = in.readString();
+ mDomainSuffices = in.readString();
+ mRouteList = in.readString();
+ mSavedUsername = in.readString();
+ }
+
+ public static final Parcelable.Creator<VpnProfile> CREATOR =
+ new Parcelable.Creator<VpnProfile>() {
+ public VpnProfile createFromParcel(Parcel in) {
+ VpnType type = Enum.valueOf(VpnType.class, in.readString());
+ boolean customized = in.readInt() > 0;
+ VpnProfile p = new VpnManager(null).createVpnProfile(type,
+ customized);
+ if (p == null) return null;
+ p.readFromParcel(in);
+ return p;
+ }
+
+ public VpnProfile[] newArray(int size) {
+ return new VpnProfile[size];
+ }
+ };
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(getType().toString());
+ parcel.writeInt(mIsCustomized ? 1 : 0);
+ parcel.writeString(mName);
+ parcel.writeString(mId);
+ parcel.writeString(mServerName);
+ parcel.writeString(mDomainSuffices);
+ parcel.writeString(mRouteList);
+ parcel.writeString(mSavedUsername);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/vpn/java/android/net/vpn/VpnState.java b/vpn/java/android/net/vpn/VpnState.java
new file mode 100644
index 0000000..ebd9364
--- /dev/null
+++ b/vpn/java/android/net/vpn/VpnState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+/**
+ * Enumeration of all VPN states.
+ *
+ * A normal VPN connection lifetime starts in {@link IDLE}. When a new
+ * connection is about to be set up, it goes to {@link CONNECTING} and then
+ * {@link CONNECTED} if successful; back to {@link IDLE} if failed.
+ * When the connection is about to be torn down, it goes to
+ * {@link DISCONNECTING} and then {@link IDLE}.
+ * {@link CANCELLED} is a state when a VPN connection attempt is aborted, and
+ * is in transition to {@link IDLE}.
+ * {@hide}
+ */
+public enum VpnState {
+ CONNECTING, DISCONNECTING, CANCELLED, CONNECTED, IDLE
+}
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
new file mode 100644
index 0000000..c7df943
--- /dev/null
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+/**
+ * Enumeration of all supported VPN types.
+ * {@hide}
+ */
+public enum VpnType {
+ PPTP("PPTP", "", PptpProfile.class),
+ L2TP("L2TP", "", L2tpProfile.class),
+ L2TP_IPSEC_PSK("L2TP/IPSec PSK", "Pre-shared key based L2TP/IPSec VPN",
+ L2tpIpsecPskProfile.class),
+ L2TP_IPSEC("L2TP/IPSec CRT", "Certificate based L2TP/IPSec VPN",
+ L2tpIpsecProfile.class);
+
+ private String mDisplayName;
+ private String mDescription;
+ private Class<? extends VpnProfile> mClass;
+
+ VpnType(String displayName, String description,
+ Class<? extends VpnProfile> klass) {
+ mDisplayName = displayName;
+ mDescription = description;
+ mClass = klass;
+ }
+
+ public String getDisplayName() {
+ return mDisplayName;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public Class<? extends VpnProfile> getProfileClass() {
+ return mClass;
+ }
+}