diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2009-07-25 19:52:22 -0700 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2009-07-25 21:15:25 -0700 |
commit | 9261bae1d2a769cb7453d2cadb6040be38ec86e5 (patch) | |
tree | b9edeeb20bf20eb9f76902a9671dbe10e871717b /libs | |
parent | 4cce5bd5ccc7c8468d0f8cc359525f82a45dedec (diff) | |
parent | 4d3b5c1e36f2a3746a1c87f8af97d4fe97e8f49e (diff) | |
download | frameworks_native-9261bae1d2a769cb7453d2cadb6040be38ec86e5.zip frameworks_native-9261bae1d2a769cb7453d2cadb6040be38ec86e5.tar.gz frameworks_native-9261bae1d2a769cb7453d2cadb6040be38ec86e5.tar.bz2 |
Merge korg/donut into korg/master
Diffstat (limited to 'libs')
44 files changed, 2297 insertions, 1033 deletions
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 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream( } 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 @@ public: 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 @@ public: }; 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 @@ public: 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 43df7dd..2817a0d 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -499,7 +499,8 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) } #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); @@ -655,16 +656,12 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) if (stream == AudioSystem::VOICE_CALL || stream == AudioSystem::BLUETOOTH_SCO) { - float hwValue = value; + float hwValue; if (stream == AudioSystem::VOICE_CALL) { hwValue = (float)AudioSystem::logToLinear(value)/100.0f; - // FIXME: This is a temporary fix to re-base the internally - // generated in-call audio so that it is never muted, which is - // already the case for the hardware routed in-call audio. - // When audio stream handling is reworked, this should be - // addressed more cleanly. Fixes #1324; see discussion at - // http://review.source.android.com/8224 - value = value * 0.99 + 0.01; + // offset value to reflect actual hardware volume that never reaches 0 + // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java) + value = 0.01 + 0.99 * value; } else { // (type == AudioSystem::BLUETOOTH_SCO) hwValue = 1.0f; } @@ -681,6 +678,11 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) mA2dpMixerThread->setStreamVolume(stream, value); #endif + mHardwareMixerThread->setStreamVolume(stream, value); +#ifdef WITH_A2DP + mA2dpMixerThread->setStreamVolume(stream, value); +#endif + return ret; } @@ -718,15 +720,14 @@ float AudioFlinger::streamVolume(int stream) const if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return 0.0f; } - float value = mHardwareMixerThread->streamVolume(stream); + float volume = mHardwareMixerThread->streamVolume(stream); + // remove correction applied by setStreamVolume() if (stream == AudioSystem::VOICE_CALL) { - // FIXME: Re-base internally generated in-call audio, - // reverse of above in setStreamVolume. - value = (value - 0.01) / 0.99; + volume = (volume - 0.01) / 0.99 ; } - return value; + return volume; } bool AudioFlinger::streamMute(int stream) const @@ -824,24 +825,22 @@ void AudioFlinger::handleForcedSpeakerRoute(int command) { 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); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - mAudioHardware->setMasterVolume(0); - 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); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume()); - mHardwareStatus = AUDIO_HW_IDLE; + 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); } @@ -902,7 +901,7 @@ void AudioFlinger::handleRouteDisablesA2dp_l(int routes) } LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount); } else { - LOGE("mA2dpDisableCount is already zero"); + LOGV("mA2dpDisableCount is already zero"); } } } @@ -1289,7 +1288,7 @@ sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l( 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; @@ -1497,18 +1496,6 @@ status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track) return status; } -// removeTrack_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::removeTrack_l(wp<Track> track, int name) -{ - sp<Track> t = track.promote(); - if (t!=NULL && (t->mState <= TrackBase::STOPPED)) { - t->reset(); - deleteTrackName_l(name); - removeActiveTrack_l(track); - mAudioFlinger->mWaitWorkCV.broadcast(); - } -} - // destroyTrack_l() must be called with AudioFlinger::mLock held void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track) { @@ -1577,7 +1564,6 @@ size_t AudioFlinger::MixerThread::getOutputFrameCount() AudioFlinger::MixerThread::TrackBase::TrackBase( const sp<MixerThread>& mixerThread, const sp<Client>& client, - int streamType, uint32_t sampleRate, int format, int channelCount, @@ -1587,7 +1573,6 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( : RefBase(), mMixerThread(mixerThread), mClient(client), - mStreamType(streamType), mFrameCount(0), mState(IDLE), mClientTid(-1), @@ -1618,8 +1603,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( 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)); @@ -1642,8 +1627,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( 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 @@ -1704,7 +1689,7 @@ int AudioFlinger::MixerThread::TrackBase::sampleRate() const { } 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 { @@ -1714,7 +1699,7 @@ void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t // Check validity of returned pointer in case the track control block would have been corrupted. if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || - cblk->channels == 2 && ((unsigned long)bufferStart & 3) ) { + (cblk->channels == 2 && ((unsigned long)bufferStart & 3))) { LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ server %d, serverBase %d, user %d, userBase %d, channels %d", bufferStart, bufferEnd, mBuffer, mBufferEnd, @@ -1737,12 +1722,13 @@ AudioFlinger::MixerThread::Track::Track( 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() @@ -1750,7 +1736,6 @@ AudioFlinger::MixerThread::Track::~Track() wp<Track> weak(this); // never create a strong ref from the dtor Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); mState = TERMINATED; - mMixerThread->removeTrack_l(weak, mName); } void AudioFlinger::MixerThread::Track::destroy() @@ -1927,15 +1912,15 @@ void AudioFlinger::MixerThread::Track::setVolume(float left, float right) 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) { } @@ -2260,7 +2245,7 @@ status_t AudioFlinger::TrackHandle::onTransact( sp<IAudioRecord> AudioFlinger::openRecord( pid_t pid, - int streamType, + int inputSource, uint32_t sampleRate, int format, int channelCount, @@ -2283,18 +2268,12 @@ sp<IAudioRecord> AudioFlinger::openRecord( 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; @@ -2326,7 +2305,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( 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) { @@ -2432,7 +2411,9 @@ bool AudioFlinger::AudioRecordThread::threadLoop() 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 db5cc74..8e47b29 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -139,7 +139,7 @@ public: // record interface virtual sp<IAudioRecord> openRecord( pid_t pid, - int streamType, + int inputSource, uint32_t sampleRate, int format, int channelCount, @@ -232,7 +232,6 @@ private: TrackBase(const sp<MixerThread>& mixerThread, const sp<Client>& client, - int streamType, uint32_t sampleRate, int format, int channelCount, @@ -260,10 +259,6 @@ private: return mCblk; } - int type() const { - return mStreamType; - } - int format() const { return mFormat; } @@ -293,7 +288,6 @@ private: sp<Client> mClient; sp<IMemory> mCblkMemory; audio_track_cblk_t* mCblk; - int mStreamType; void* mBuffer; void* mBufferEnd; uint32_t mFrameCount; @@ -328,6 +322,11 @@ private: 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 @@ private: int8_t mRetryCount; sp<IMemory> mSharedBuffer; bool mResetDone; + int mStreamType; }; // end of Track // record track @@ -371,7 +371,7 @@ private: 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 @@ private: 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 @@ private: virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); bool mOverflow; + int mInputSource; }; // playback track @@ -501,7 +504,6 @@ private: MixerThread& operator = (const MixerThread&); status_t addTrack_l(const sp<Track>& track); - void removeTrack_l(wp<Track> track, int name); void destroyTrack_l(const sp<Track>& track); int getTrackName_l(); void deleteTrackName_l(int name); 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 @@ void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) { } 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 @@ public: status_t *status=0); virtual AudioStreamIn* openInputStream( + int inputSource, int format, int channelCount, uint32_t sampleRate, diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp index ac76a19..cc1bd8f 100644 --- a/libs/audioflinger/AudioHardwareInterface.cpp +++ b/libs/audioflinger/AudioHardwareInterface.cpp @@ -53,7 +53,7 @@ static const char* routeStrings[] = "EARPIECE ", "SPEAKER ", "BLUETOOTH ", - "HEADSET " + "HEADSET ", "BLUETOOTH_A2DP " }; static const char* routeNone = "NONE"; 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 @@ AudioStreamOut* AudioHardwareStub::openOutputStream( } 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 @@ public: 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 @@ LOCAL_SRC_FILES:= \ 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 @@ void DisplayHardware::init(uint32_t dpy) 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/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp index eb75f99..7168bf2 100644 --- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp +++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp @@ -573,7 +573,11 @@ void GPUHardware::binderDied(const wp<IBinder>& who) sp<GPUHardwareInterface> GPUFactory::getGPU() { - return new GPUHardware(); + sp<GPUHardwareInterface> gpu; + if (access("/dev/hw3d", F_OK) == 0) { + gpu = new GPUHardware(); + } + return gpu; } // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index f65d669..96395a8 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -108,7 +108,7 @@ status_t Layer::setBuffers( Client* client, // we always force a 4-byte aligned bpr. uint32_t alignment = 1; - if (flags & ISurfaceComposer::eGPU) { + if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) { // FIXME: this value should come from the h/w alignment = 8; // FIXME: this is msm7201A specific, as its GPU only supports 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 @@ status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment, } 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 c2adf07..6dab372 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -62,6 +62,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 { @@ -185,7 +192,6 @@ SurfaceFlinger::SurfaceFlinger() mDebugCpu(0), mDebugFps(0), mDebugBackground(0), - mDebugNoBootAnimation(0), mSyncObject(), mDeplayedTransactionPending(0), mConsoleSignals(0), @@ -208,14 +214,11 @@ void SurfaceFlinger::init() 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() @@ -242,6 +245,9 @@ sp<IMemory> SurfaceFlinger::getCblk() const status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback, gpu_info_t* gpu) { + if (mGPU == 0) + return INVALID_OPERATION; + IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); status_t err = mGPU->request(pid, callback, gpu); @@ -250,6 +256,9 @@ status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback, status_t SurfaceFlinger::revokeGPU() { + if (mGPU == 0) + return INVALID_OPERATION; + return mGPU->friendlyRevoke(); } @@ -319,11 +328,8 @@ void SurfaceFlinger::bootFinished() { 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() @@ -451,10 +457,10 @@ status_t SurfaceFlinger::readyToRun() 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; } @@ -766,10 +772,11 @@ void SurfaceFlinger::computeVisibleRegions( 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); @@ -778,7 +785,7 @@ void SurfaceFlinger::computeVisibleRegions( // 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); @@ -1538,13 +1545,13 @@ status_t SurfaceFlinger::onTransact( // 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; @@ -1601,10 +1608,14 @@ status_t SurfaceFlinger::onTransact( } return NO_ERROR; case 1005: // ask GPU revoke - mGPU->friendlyRevoke(); + if (mGPU != 0) { + mGPU->friendlyRevoke(); + } return NO_ERROR; case 1006: // revoke GPU - mGPU->unconditionalRevoke(); + if (mGPU != 0) { + mGPU->unconditionalRevoke(); + } return NO_ERROR; case 1007: // set mFreezeCount mFreezeCount = data.readInt32(); 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 @@ private: 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 @@ private: 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 0ccd71f..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" @@ -98,7 +100,7 @@ sp<MemoryDealer> SurfaceHeapManager::createHeap( } } - if (flags & ISurfaceComposer::eGPU) { + if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) { // FIXME: this is msm7201A specific, where gpu surfaces may not be secure if (!(flags & ISurfaceComposer::eSecure)) { // if GPU doesn't work, we try eHardware 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 @@ LOCAL_SRC_FILES:= \ 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 b3cbda1..975594f 100644 --- a/libs/ui/Camera.cpp +++ b/libs/ui/Camera.cpp @@ -64,34 +64,27 @@ Camera::Camera() init(); } -Camera::Camera(const sp<ICamera>& camera) +// construct a camera client from an existing camera remote +sp<Camera> Camera::create(const sp<ICamera>& camera) { - init(); - // connect this client to existing camera remote - if (camera->connect(this) == NO_ERROR) { - mStatus = NO_ERROR; - mCamera = camera; - camera->asBinder()->linkToDeath(this); + LOGV("create"); + if (camera == 0) { + LOGE("camera remote is a NULL pointer"); + return 0; + } + + sp<Camera> c = new Camera(); + if (camera->connect(c) == NO_ERROR) { + c->mStatus = NO_ERROR; + c->mCamera = camera; + camera->asBinder()->linkToDeath(c); } + return c; } 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() @@ -120,7 +113,6 @@ void Camera::disconnect() { LOGV("disconnect"); if (mCamera != 0) { - mErrorCallback = 0; mCamera->disconnect(); mCamera = 0; } @@ -157,21 +149,21 @@ status_t Camera::unlock() 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; @@ -179,7 +171,7 @@ status_t Camera::setPreviewDisplay(const sp<ISurface>& surface) } -// start preview mode, must call setPreviewDisplay first +// start preview mode status_t Camera::startPreview() { LOGV("startPreview"); @@ -278,123 +270,49 @@ String8 Camera::getParameters() const return params; } -void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie) -{ - LOGV("setAutoFocusCallback"); - mAutoFocusCallback = cb; - mAutoFocusCallbackCookie = cookie; -} - -void Camera::setShutterCallback(shutter_callback cb, void *cookie) -{ - LOGV("setShutterCallback"); - mShutterCallback = cb; - mShutterCallbackCookie = cookie; -} - -void Camera::setRawCallback(frame_callback cb, void *cookie) +void Camera::setListener(const sp<CameraListener>& listener) { - LOGV("setRawCallback"); - mRawCallback = cb; - mRawCallbackCookie = cookie; -} - -void Camera::setJpegCallback(frame_callback cb, void *cookie) -{ - LOGV("setJpegCallback"); - mJpegCallback = cb; - mJpegCallbackCookie = cookie; + Mutex::Autolock _l(mLock); + mListener = listener; } -void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag) +void Camera::setPreviewCallbackFlags(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) +// callback from camera service +void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { - LOGV("setErrorCallback"); - mErrorCallback = cb; - mErrorCallbackCookie = cookie; -} - -void Camera::autoFocusCallback(bool focused) -{ - LOGV("autoFocusCallback"); - if (mAutoFocusCallback) { - mAutoFocusCallback(focused, mAutoFocusCallbackCookie); - } -} - -void Camera::shutterCallback() -{ - LOGV("shutterCallback"); - if (mShutterCallback) { - mShutterCallback(mShutterCallbackCookie); - } -} - -void Camera::rawCallback(const sp<IMemory>& picture) -{ - LOGV("rawCallback"); - if (mRawCallback) { - mRawCallback(picture, mRawCallbackCookie); + sp<CameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; } -} - -// callback from camera service when image is ready -void Camera::jpegCallback(const sp<IMemory>& picture) -{ - LOGV("jpegCallback"); - if (mJpegCallback) { - mJpegCallback(picture, mJpegCallbackCookie); + if (listener != NULL) { + listener->notify(msgType, ext1, ext2); } } -// callback from camera service when preview frame is ready -void Camera::previewCallback(const sp<IMemory>& frame) +// callback from camera service when frame or image is ready +void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) { - LOGV("frameCallback"); - if (mPreviewCallback) { - mPreviewCallback(frame, mPreviewCallbackCookie); + sp<CameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; } -} - -// callback from camera service when a recording frame is ready -void Camera::recordingCallback(const sp<IMemory>& frame) -{ - LOGV("recordingCallback"); - if (mRecordingCallback) { - mRecordingCallback(frame, mRecordingCallbackCookie); - } -} - -// callback from camera service when an error occurs in preview or takePicture -void Camera::errorCallback(status_t error) -{ - LOGV("errorCallback"); - if (mErrorCallback) { - mErrorCallback(error, mErrorCallbackCookie); + 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/ICameraClient.cpp b/libs/ui/ICameraClient.cpp index 4bec9d2..c6cf75c 100644 --- a/libs/ui/ICameraClient.cpp +++ b/libs/ui/ICameraClient.cpp @@ -25,13 +25,8 @@ namespace android { enum { - SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, - RAW_CALLBACK, - JPEG_CALLBACK, - PREVIEW_CALLBACK, - ERROR_CALLBACK, - AUTOFOCUS_CALLBACK, - RECORDING_CALLBACK, + NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, + DATA_CALLBACK, }; class BpCameraClient: public BpInterface<ICameraClient> @@ -42,74 +37,29 @@ public: { } - // callback to let the app know the shutter has closed, ideal for playing the shutter sound - void shutterCallback() + // generic callback from camera service to app + void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { - LOGV("shutterCallback"); + LOGV("notifyCallback"); Parcel data, reply; data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + data.writeInt32(msgType); + data.writeInt32(ext1); + data.writeInt32(ext2); + remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); } - // callback from camera service to app with picture data - void rawCallback(const sp<IMemory>& picture) + // generic data callback from camera service to app with image data + void dataCallback(int32_t msgType, const sp<IMemory>& imageData) { - LOGV("rawCallback"); + LOGV("dataCallback"); Parcel data, reply; data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(picture->asBinder()); - remote()->transact(RAW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + data.writeInt32(msgType); + data.writeStrongBinder(imageData->asBinder()); + remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); } - // callback from camera service to app with picture data - void jpegCallback(const sp<IMemory>& picture) - { - LOGV("jpegCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(picture->asBinder()); - remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app with preview frame data - void previewCallback(const sp<IMemory>& frame) - { - LOGV("previewCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(frame->asBinder()); - remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app with recording frame data - void recordingCallback(const sp<IMemory>& frame) - { - LOGV("recordingCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeStrongBinder(frame->asBinder()); - remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app to report error - void errorCallback(status_t error) - { - LOGV("errorCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt32(error); - remote()->transact(ERROR_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - // callback from camera service to app to report autofocus completion - void autoFocusCallback(bool focused) - { - LOGV("autoFocusCallback"); - Parcel data, reply; - data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); - data.writeInt32(focused); - remote()->transact(AUTOFOCUS_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } }; IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient"); @@ -126,52 +76,21 @@ status_t BnCameraClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { - case SHUTTER_CALLBACK: { - LOGV("SHUTTER_CALLBACK"); + case NOTIFY_CALLBACK: { + LOGV("NOTIFY_CALLBACK"); CHECK_INTERFACE(ICameraClient, data, reply); - shutterCallback(); + int32_t msgType = data.readInt32(); + int32_t ext1 = data.readInt32(); + int32_t ext2 = data.readInt32(); + notifyCallback(msgType, ext1, ext2); return NO_ERROR; } break; - case RAW_CALLBACK: { + case DATA_CALLBACK: { LOGV("RAW_CALLBACK"); CHECK_INTERFACE(ICameraClient, data, reply); - sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder()); - rawCallback(picture); - return NO_ERROR; - } break; - case JPEG_CALLBACK: { - LOGV("JPEG_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder()); - jpegCallback(picture); - return NO_ERROR; - } break; - case PREVIEW_CALLBACK: { - LOGV("PREVIEW_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder()); - previewCallback(frame); - return NO_ERROR; - } break; - case RECORDING_CALLBACK: { - LOGV("RECORDING_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder()); - recordingCallback(frame); - return NO_ERROR; - } break; - case ERROR_CALLBACK: { - LOGV("ERROR_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - status_t error = data.readInt32(); - errorCallback(error); - return NO_ERROR; - } break; - case AUTOFOCUS_CALLBACK: { - LOGV("AUTOFOCUS_CALLBACK"); - CHECK_INTERFACE(ICameraClient, data, reply); - bool focused = (bool)data.readInt32(); - autoFocusCallback(focused); + int32_t msgType = data.readInt32(); + sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder()); + dataCallback(msgType, imageData); return NO_ERROR; } break; default: 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 @@ status_t BnSurfaceFlingerClient::onTransact( 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(overlay_handle_t handle, const sp<IOverlay>& channel, 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 @@ sp<OverlayRef> OverlayRef::readFromParcel(const Parcel& data) { 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 @@ status_t OverlayRef::writeToParcel(Parcel* reply, const sp<OverlayRef>& o) { 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 @@ Rect& Rect::offsetBy(int x, int y) 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 cdb8ca2..9bdd64a 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -116,7 +116,9 @@ LOCAL_SRC_FILES:= \ ProcessState.cpp \ IPermissionController.cpp \ IServiceManager.cpp \ - Unicode.cpp + Unicode.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 @@ const void* _FileAsset::ensureAlignment(FileMap* map) 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 ResTable* AssetManager::getResTable(bool required) const 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 @@ const ResTable* AssetManager::getResTable(bool required) const 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 @@ AssetDir* AssetManager::openDir(const char* dirName) } /* + * 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 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg 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 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg 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 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg dirs.add(subdirName); } - //printf("FOUND: dir '%s'\n", (const char*) subdirName); + //printf("FOUND: dir '%s'\n", subdirName.string()); } } } @@ -1455,7 +1536,8 @@ Mutex AssetManager::SharedZip::gLock; 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 @@ Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset) 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 @@ bool AssetManager::SharedZip::isUpToDate() 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 @@ ZipFileRO* AssetManager::ZipSet::getZip(const String8& path) 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 @@ Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path) 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 @@ Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path, 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 index e931d99..e931d99 100644 --- a/libs/utils/characterData.h +++ b/libs/utils/CharacterData.h diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp index 4225e67..b0e3750 100644 --- a/libs/utils/Parcel.cpp +++ b/libs/utils/Parcel.cpp @@ -409,12 +409,16 @@ status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) 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 @@ status_t Parcel::writeWeakBinder(const wp<IBinder>& val) 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 @@ wp<IBinder> Parcel::readWeakBinder() const } -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,30 +939,15 @@ native_handle* Parcel::readNativeHandle(native_handle* (*alloc)(void*, int, int) 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 2ad3bfe..109f28d 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -544,7 +544,7 @@ ResXMLParser::event_code_t ResXMLParser::next() 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 @@ const uint16_t* ResXMLParser::getComment(size_t* outLen) const 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 @@ ssize_t ResXMLParser::getTextValue(Res_value* outValue) const 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 @@ const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const 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 @@ const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const 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 @@ const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const 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 @@ size_t ResXMLParser::getAttributeCount() const 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 @@ const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) 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 @@ const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const 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 @@ const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const 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 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const 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::Type 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 @@ struct ResTable::Package } } + 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 @@ struct ResTable::Package // 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 @@ struct ResTable::PackageGroup } } + 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 @@ status_t ResTable::add(Asset* asset, void* cookie, bool copyData) 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 @@ void ResTable::uninit() 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 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const 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; } @@ -1820,7 +1857,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag } } - if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) { + if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) { continue; } @@ -2331,13 +2368,13 @@ nope: 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 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, 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 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, 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 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, 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 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, #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) +{ + 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 { - printf("mError=0x%x (%s)\n", mError, strerror(mError)); + 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 @@ void ResTable::print() const 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 @@ void ResTable::print() const 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 ResTable::print() const (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/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 |