diff options
68 files changed, 1369 insertions, 3516 deletions
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp index bbd1a1b..4b4b9b9 100644 --- a/cmds/keystore/keystore.cpp +++ b/cmds/keystore/keystore.cpp @@ -708,11 +708,10 @@ static struct user { uid_t euid; uint32_t perms; } users[] = { - {AID_SYSTEM, ~0, ~GET}, + {AID_SYSTEM, ~0, ~0}, {AID_VPN, AID_SYSTEM, GET}, {AID_WIFI, AID_SYSTEM, GET}, {AID_ROOT, AID_SYSTEM, GET}, - {AID_KEYCHAIN, AID_SYSTEM, TEST | GET | SAW}, {~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW}, }; diff --git a/cmds/keystore/test-keystore b/cmds/keystore/test-keystore index 82b276f..3be51b3 100755 --- a/cmds/keystore/test-keystore +++ b/cmds/keystore/test-keystore @@ -116,11 +116,12 @@ function test_basic() { expect "1 No error" expect "baz" - log "system does not have access to read any keys" + log "get baz" keystore system g baz - expect "6 Permission denied" - - log "however, root can read system user keys (as can wifi or vpn users)" + expect "1 No error" + expect "quux" + + log "root can read system user keys (as can wifi or vpn users)" keystore root g baz expect "1 No error" expect "quux" diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h index 74d2cc7..2d0db00 100644 --- a/include/binder/IMemory.h +++ b/include/binder/IMemory.h @@ -43,6 +43,7 @@ public: virtual void* getBase() const = 0; virtual size_t getSize() const = 0; virtual uint32_t getFlags() const = 0; + virtual uint32_t getOffset() const = 0; // these are there just for backward source compatibility int32_t heapID() const { return getHeapID(); } diff --git a/include/binder/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h index 2f2e31b..bbbda9c 100644 --- a/include/binder/MemoryHeapBase.h +++ b/include/binder/MemoryHeapBase.h @@ -27,7 +27,7 @@ namespace android { // --------------------------------------------------------------------------- -class MemoryHeapBase : public virtual BnMemoryHeap +class MemoryHeapBase : public virtual BnMemoryHeap { public: enum { @@ -38,12 +38,12 @@ public: NO_CACHING = 0x00000200 }; - /* + /* * maps the memory referenced by fd. but DOESN'T take ownership * of the filedescriptor (it makes a copy with dup() */ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0); - + /* * maps memory from the given device */ @@ -61,9 +61,10 @@ public: virtual void* getBase() const; virtual size_t getSize() const; virtual uint32_t getFlags() const; + virtual uint32_t getOffset() const; const char* getDevice() const; - + /* this closes this heap -- use carefully */ void dispose(); @@ -74,12 +75,12 @@ public: mDevice = device; return mDevice ? NO_ERROR : ALREADY_EXISTS; } - + protected: MemoryHeapBase(); // init() takes ownership of fd status_t init(int fd, void *base, int size, - int flags = 0, const char* device = NULL); + int flags = 0, const char* device = NULL); private: status_t mapfd(int fd, size_t size, uint32_t offset = 0); @@ -90,6 +91,7 @@ private: uint32_t mFlags; const char* mDevice; bool mNeedUnmap; + uint32_t mOffset; }; // --------------------------------------------------------------------------- diff --git a/include/binder/Permission.h b/include/binder/Permission.h deleted file mode 100644 index 9542d50..0000000 --- a/include/binder/Permission.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef BINDER_PERMISSION_H -#define BINDER_PERMISSION_H - -#include <stdint.h> -#include <unistd.h> - -#include <utils/SortedVector.h> -#include <utils/String16.h> -#include <utils/threads.h> - -namespace android { -// --------------------------------------------------------------------------- - -/* - * Permission caches the result of the permission check for the given - * permission name and the provided uid/pid. It also handles a few - * known cases efficiently (caller is in the same process or is root). - * The package manager does something similar but lives in dalvik world - * and is therefore extremely slow to access. - */ - -class Permission -{ -public: - Permission(char const* name); - Permission(const String16& name); - Permission(const Permission& rhs); - virtual ~Permission(); - - bool operator < (const Permission& rhs) const; - - // checks the current binder call's caller has access to this permission - bool checkCalling() const; - - // checks the specified pid/uid has access to this permission - bool check(pid_t pid, uid_t uid) const; - -protected: - virtual bool doCheckPermission(pid_t pid, uid_t uid) const; - -private: - Permission& operator = (const Permission& rhs) const; - const String16 mPermissionName; - mutable SortedVector<uid_t> mGranted; - const pid_t mPid; - mutable Mutex mLock; -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif /* BINDER_PERMISSION_H */ diff --git a/include/binder/PermissionCache.h b/include/binder/PermissionCache.h new file mode 100644 index 0000000..1171d48 --- /dev/null +++ b/include/binder/PermissionCache.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BINDER_PERMISSION_H +#define BINDER_PERMISSION_H + +#include <stdint.h> +#include <unistd.h> + +#include <utils/String16.h> +#include <utils/Singleton.h> + +namespace android { +// --------------------------------------------------------------------------- + +/* + * PermissionCache caches permission checks for a given uid. + * + * Currently the cache is not updated when there is a permission change, + * for instance when an application is uninstalled. + * + * IMPORTANT: for the reason stated above, only system permissions are safe + * to cache. This restriction may be lifted at a later time. + * + */ + +class PermissionCache : Singleton<PermissionCache> { + struct Entry { + String16 name; + uid_t uid; + bool granted; + inline bool operator < (const Entry& e) const { + return (uid == e.uid) ? (name < e.name) : (uid < e.uid); + } + }; + mutable Mutex mLock; + // we pool all the permission names we see, as many permissions checks + // will have identical names + SortedVector< String16 > mPermissionNamesPool; + // this is our cache per say. it stores pooled names. + SortedVector< Entry > mCache; + + // free the whole cache, but keep the permission name pool + void purge(); + + status_t check(bool* granted, + const String16& permission, uid_t uid) const; + + void cache(const String16& permission, uid_t uid, bool granted); + +public: + PermissionCache(); + + static bool checkCallingPermission(const String16& permission); + + static bool checkCallingPermission(const String16& permission, + int32_t* outPid, int32_t* outUid); + + static bool checkPermission(const String16& permission, + pid_t pid, uid_t uid); +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif /* BINDER_PERMISSION_H */ diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 9294df6..e36360c 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -46,17 +46,20 @@ public: enum { NUM_BUFFER_SLOTS = 32 }; struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called from queueBuffer() is the FIFO is - // empty. You can use SurfaceTexture::getQueuedCount() to - // figure out if there are more frames waiting. - // This is called without any lock held can be called concurrently by - // multiple threads. + // onFrameAvailable() is called from queueBuffer() each time an + // additional frame becomes available for consumption. This means that + // frames that are queued while in asynchronous mode only trigger the + // callback if no previous frames are pending. Frames queued while in + // synchronous mode always trigger the callback. + // + // This is called without any lock held and can be called concurrently + // by multiple threads. virtual void onFrameAvailable() = 0; }; // tex indicates the name OpenGL texture to which images are to be streamed. // This texture name cannot be changed once the SurfaceTexture is created. - SurfaceTexture(GLuint tex); + SurfaceTexture(GLuint tex, bool allowSynchronousMode = true); virtual ~SurfaceTexture(); @@ -101,11 +104,6 @@ public: // target texture belongs is bound to the calling thread. status_t updateTexImage(); - // getqueuedCount returns the number of queued frames waiting in the - // FIFO. In asynchronous mode, this always returns 0 or 1 since - // frames are not accumulating in the FIFO. - size_t getQueuedCount() const; - // setBufferCountServer set the buffer count. If the client has requested // a buffer count using setBufferCount, the server-buffer count will // take effect once the client sets the count back to zero. @@ -141,7 +139,7 @@ public: // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. - void setFrameAvailableListener(const sp<FrameAvailableListener>& l); + void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); // getAllocator retrieves the binder object that must be referenced as long // as the GraphicBuffers dequeued from this SurfaceTexture are referenced. @@ -345,7 +343,7 @@ private: uint32_t mNextTransform; // mTexName is the name of the OpenGL texture to which streamed images will - // be bound when updateTexImage is called. It is set at construction time + // be bound when updateTexImage is called. It is set at construction time // changed with a call to setTexName. const GLuint mTexName; @@ -361,6 +359,9 @@ private: // mSynchronousMode whether we're in synchronous mode or not bool mSynchronousMode; + // mAllowSynchronousMode whether we allow synchronous mode or not + const bool mAllowSynchronousMode; + // mDequeueCondition condition used for dequeueBuffer in synchronous mode mutable Condition mDequeueCondition; diff --git a/include/pim/EventRecurrence.h b/include/pim/EventRecurrence.h deleted file mode 100644 index 1ceda41..0000000 --- a/include/pim/EventRecurrence.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2006 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 _PIM_EVENT_RECURRENCE_H -#define _PIM_EVENT_RECURRENCE_H - -#include <utils/String16.h> - -namespace android { - -struct EventRecurrence -{ -public: - EventRecurrence(); - ~EventRecurrence(); - - status_t parse(const String16&); - - - enum freq_t { - SECONDLY = 1, - MINUTELY = 2, - HOURLY = 3, - DAILY = 4, - WEEKLY = 5, - MONTHLY = 6, - YEARLY = 7 - }; - - enum { - SU = 0x00010000, - MO = 0x00020000, - TU = 0x00040000, - WE = 0x00080000, - TH = 0x00100000, - FR = 0x00200000, - SA = 0x00400000 - }; - - freq_t freq; - String16 until; - int count; - int interval; - int* bysecond; - int bysecondCount; - int* byminute; - int byminuteCount; - int* byhour; - int byhourCount; - int* byday; - int* bydayNum; - int bydayCount; - int* bymonthday; - int bymonthdayCount; - int* byyearday; - int byyeardayCount; - int* byweekno; - int byweeknoCount; - int* bymonth; - int bymonthCount; - int* bysetpos; - int bysetposCount; - int wkst; -}; - -}; // namespace android - -#endif // _PIM_EVENT_RECURRENCE_H diff --git a/include/private/surfaceflinger/LayerState.h b/include/private/surfaceflinger/LayerState.h index d7fe572..d2fed41 100644 --- a/include/private/surfaceflinger/LayerState.h +++ b/include/private/surfaceflinger/LayerState.h @@ -29,6 +29,7 @@ namespace android { class Parcel; +class ISurfaceComposerClient; struct layer_state_t { @@ -68,6 +69,13 @@ struct layer_state_t { Region transparentRegion; }; +struct ComposerState { + sp<ISurfaceComposerClient> client; + layer_state_t state; + status_t write(Parcel& output) const; + status_t read(const Parcel& input); +}; + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h index e1b6b57..d3b2062 100644 --- a/include/surfaceflinger/IGraphicBufferAlloc.h +++ b/include/surfaceflinger/IGraphicBufferAlloc.h @@ -37,7 +37,7 @@ public: /* Create a new GraphicBuffer for the client to use. */ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage) = 0; + PixelFormat format, uint32_t usage, status_t* error) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index 03fd01b..dba98a3 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -34,6 +34,7 @@ namespace android { // ---------------------------------------------------------------------------- class IMemoryHeap; +class ComposerState; class ISurfaceComposer : public IInterface { @@ -105,8 +106,7 @@ public: virtual sp<IMemoryHeap> getCblk() const = 0; /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ - virtual void openGlobalTransaction() = 0; - virtual void closeGlobalTransaction() = 0; + virtual void setTransactionState(const Vector<ComposerState>& state) = 0; /* [un]freeze display. requires ACCESS_SURFACE_FLINGER permission */ virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0; @@ -149,8 +149,7 @@ public: CREATE_CONNECTION, CREATE_GRAPHIC_BUFFER_ALLOC, GET_CBLK, - OPEN_GLOBAL_TRANSACTION, - CLOSE_GLOBAL_TRANSACTION, + SET_TRANSACTION_STATE, SET_ORIENTATION, FREEZE_DISPLAY, UNFREEZE_DISPLAY, diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h index 2e75a0e..6e9a654 100644 --- a/include/surfaceflinger/ISurfaceComposerClient.h +++ b/include/surfaceflinger/ISurfaceComposerClient.h @@ -37,8 +37,6 @@ typedef int32_t DisplayID; // ---------------------------------------------------------------------------- -class layer_state_t; - class ISurfaceComposerClient : public IInterface { public: @@ -69,11 +67,6 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t destroySurface(SurfaceID sid) = 0; - - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t setState(int32_t count, const layer_state_t* states) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 8845dc9..dc2a845 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -40,6 +40,7 @@ namespace android { class GraphicBuffer; class GraphicBufferMapper; class IOMX; +class ISurfaceTexture; class Rect; class Surface; class SurfaceComposerClient; @@ -154,6 +155,7 @@ public: bool isValid(); uint32_t getFlags() const { return mFlags; } uint32_t getIdentity() const { return mIdentity; } + sp<ISurfaceTexture> getSurfaceTexture(); // the lock/unlock APIs must be used from the same thread status_t lock(SurfaceInfo* info, bool blocking = true); diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 140b9f8..7fbbfb2 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -37,10 +37,12 @@ namespace android { // --------------------------------------------------------------------------- class DisplayInfo; +class Composer; class IMemoryHeap; class ISurfaceComposer; class Region; class surface_flinger_cblk_t; +struct layer_state_t; // --------------------------------------------------------------------------- @@ -59,8 +61,11 @@ public: // --------------------------------------------------------------------------- +class Composer; + class SurfaceComposerClient : public RefBase { + friend class Composer; public: SurfaceComposerClient(); virtual ~SurfaceComposerClient(); @@ -101,13 +106,7 @@ public: // All composer parameters must be changed within a transaction // several surfaces can be updated in one transaction, all changes are // committed at once when the transaction is closed. - // CloseTransaction() usually requires an IPC with the server. - - //! Open a composer transaction - status_t openTransaction(); - - //! commit the transaction - status_t closeTransaction(); + // closeGlobalTransaction() usually requires an IPC with the server. //! Open a composer transaction on all active SurfaceComposerClients. static void openGlobalTransaction(); @@ -152,19 +151,12 @@ public: private: virtual void onFirstRef(); - inline layer_state_t* get_state_l(SurfaceID id); - layer_state_t* lockLayerState(SurfaceID id); - inline void unlockLayerState(); - - mutable Mutex mLock; - SortedVector<layer_state_t> mStates; - int32_t mTransactionOpen; - layer_state_t* mPrebuiltLayerState; + Composer& getComposer(); - // these don't need to be protected because they never change - // after assignment + mutable Mutex mLock; status_t mStatus; sp<ISurfaceComposerClient> mClient; + Composer& mComposer; }; // --------------------------------------------------------------------------- diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h index de748b5..600017e 100644 --- a/include/utils/BitSet.h +++ b/include/utils/BitSet.h @@ -44,6 +44,9 @@ struct BitSet32 { // Returns true if the bit set does not contain any marked bits. inline bool isEmpty() const { return ! value; } + // Returns true if the bit set does not contain any unmarked bits. + inline bool isFull() const { return value == 0xffffffff; } + // Returns true if the specified bit is marked. inline bool hasBit(uint32_t n) const { return value & valueForBit(n); } diff --git a/include/utils/LinearTransform.h b/include/utils/LinearTransform.h new file mode 100644 index 0000000..04cb355 --- /dev/null +++ b/include/utils/LinearTransform.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 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 _LIBS_UTILS_LINEAR_TRANSFORM_H +#define _LIBS_UTILS_LINEAR_TRANSFORM_H + +#include <stdint.h> + +namespace android { + +// LinearTransform defines a structure which hold the definition of a +// transformation from single dimensional coordinate system A into coordinate +// system B (and back again). Values in A and in B are 64 bit, the linear +// scale factor is expressed as a rational number using two 32 bit values. +// +// Specifically, let +// f(a) = b +// F(b) = f^-1(b) = a +// then +// +// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero; +// +// and +// +// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero; +// +struct LinearTransform { + int64_t a_zero; + int64_t b_zero; + int32_t a_to_b_numer; + uint32_t a_to_b_denom; + + // Transform from A->B + // Returns true on success, or false in the case of a singularity or an + // overflow. + bool doForwardTransform(int64_t a_in, int64_t* b_out) const; + + // Transform from B->A + // Returns true on success, or false in the case of a singularity or an + // overflow. + bool doReverseTransform(int64_t b_in, int64_t* a_out) const; + + // Helpers which will reduce the fraction N/D using Euclid's method. + template <class T> static void reduce(T* N, T* D); + static void reduce(int32_t* N, uint32_t* D); +}; + + +} + +#endif // _LIBS_UTILS_LINEAR_TRANSFORM_H diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h index 8beec57..0e98aeb 100644 --- a/include/utils/SortedVector.h +++ b/include/utils/SortedVector.h @@ -32,6 +32,8 @@ namespace android { template <class TYPE> class SortedVector : private SortedVectorImpl { + friend class Vector<TYPE>; + public: typedef TYPE value_type; diff --git a/include/utils/Vector.h b/include/utils/Vector.h index f1e87e6..b908e2a 100644 --- a/include/utils/Vector.h +++ b/include/utils/Vector.h @@ -29,6 +29,9 @@ namespace android { +template <typename TYPE> +class SortedVector; + /*! * The main templated vector class ensuring type safety * while making use of VectorImpl. @@ -47,13 +50,17 @@ public: Vector(); Vector(const Vector<TYPE>& rhs); + explicit Vector(const SortedVector<TYPE>& rhs); virtual ~Vector(); /*! copy operator */ const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const; Vector<TYPE>& operator = (const Vector<TYPE>& rhs); - /* + const Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const; + Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs); + + /* * empty the vector */ @@ -215,6 +222,11 @@ Vector<TYPE>::Vector(const Vector<TYPE>& rhs) } template<class TYPE> inline +Vector<TYPE>::Vector(const SortedVector<TYPE>& rhs) + : VectorImpl(static_cast<const VectorImpl&>(rhs)) { +} + +template<class TYPE> inline Vector<TYPE>::~Vector() { finish_vector(); } @@ -227,6 +239,18 @@ Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) { template<class TYPE> inline const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const { + VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)); + return *this; +} + +template<class TYPE> inline +Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) { + VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)); + return *this; +} + +template<class TYPE> inline +const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const { VectorImpl::operator = (rhs); return *this; } diff --git a/include/utils/threads.h b/include/utils/threads.h index 432805e..c8e9c04 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -133,13 +133,13 @@ extern pid_t androidGetTid(); // Change the scheduling group of a particular thread. The group // should be one of the ANDROID_TGROUP constants. Returns BAD_VALUE if // grp is out of range, else another non-zero value with errno set if -// the operation failed. +// the operation failed. Thread ID zero means current thread. extern int androidSetThreadSchedulingGroup(pid_t tid, int grp); // Change the priority AND scheduling group of a particular thread. The priority // should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION // if the priority set failed, else another value if just the group set failed; -// in either case errno is set. +// in either case errno is set. Thread ID zero means current thread. extern int androidSetThreadPriority(pid_t tid, int prio); #ifdef __cplusplus diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index f9d9f25..3a12e96 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -27,7 +27,7 @@ sources := \ MemoryHeapBase.cpp \ MemoryHeapPmem.cpp \ Parcel.cpp \ - Permission.cpp \ + PermissionCache.cpp \ ProcessState.cpp \ Static.cpp diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index bc8c412..1ace8f8 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -42,11 +42,11 @@ class HeapCache : public IBinder::DeathRecipient public: HeapCache(); virtual ~HeapCache(); - + virtual void binderDied(const wp<IBinder>& who); - sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); - void free_heap(const sp<IBinder>& binder); + sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); + void free_heap(const sp<IBinder>& binder); sp<IMemoryHeap> get_heap(const sp<IBinder>& binder); void dump_heaps(); @@ -57,7 +57,7 @@ private: int32_t count; }; - void free_heap(const wp<IBinder>& binder); + void free_heap(const wp<IBinder>& binder); Mutex mHeapCacheLock; KeyedVector< wp<IBinder>, heap_info_t > mHeapCache; @@ -81,11 +81,12 @@ public: virtual void* getBase() const; virtual size_t getSize() const; virtual uint32_t getFlags() const; + virtual uint32_t getOffset() const; private: friend class IMemory; friend class HeapCache; - + // for debugging in this module static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) { return gHeapCache->find_heap(binder); @@ -97,7 +98,7 @@ private: return gHeapCache->get_heap(binder); } static inline void dump_heaps() { - gHeapCache->dump_heaps(); + gHeapCache->dump_heaps(); } void assertMapped() const; @@ -107,6 +108,7 @@ private: mutable void* mBase; mutable size_t mSize; mutable uint32_t mFlags; + mutable uint32_t mOffset; mutable bool mRealHeap; mutable Mutex mLock; }; @@ -123,7 +125,7 @@ public: BpMemory(const sp<IBinder>& impl); virtual ~BpMemory(); virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const; - + private: mutable sp<IMemoryHeap> mHeap; mutable ssize_t mOffset; @@ -203,7 +205,7 @@ IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory"); BnMemory::BnMemory() { } -BnMemory::~BnMemory() { +BnMemory::~BnMemory() { } status_t BnMemory::onTransact( @@ -229,7 +231,7 @@ status_t BnMemory::onTransact( BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl) : BpInterface<IMemoryHeap>(impl), - mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false) + mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mOffset(0), mRealHeap(false) { } @@ -242,7 +244,7 @@ BpMemoryHeap::~BpMemoryHeap() { sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); if (VERBOSE) { - LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", + LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", binder.get(), this, mSize, mHeapId); CallStack stack; stack.update(); @@ -270,6 +272,7 @@ void BpMemoryHeap::assertMapped() const if (mHeapId == -1) { mBase = heap->mBase; mSize = heap->mSize; + mOffset = heap->mOffset; android_atomic_write( dup( heap->mHeapId ), &mHeapId ); } } else { @@ -286,13 +289,14 @@ void BpMemoryHeap::assertReallyMapped() const // remote call without mLock held, worse case scenario, we end up // calling transact() from multiple threads, but that's not a problem, // only mmap below must be in the critical section. - + Parcel data, reply; data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor()); status_t err = remote()->transact(HEAP_ID, data, &reply); int parcel_fd = reply.readFileDescriptor(); ssize_t size = reply.readInt32(); uint32_t flags = reply.readInt32(); + uint32_t offset = reply.readInt32(); LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)", asBinder().get(), parcel_fd, size, err, strerror(-err)); @@ -309,7 +313,7 @@ void BpMemoryHeap::assertReallyMapped() const Mutex::Autolock _l(mLock); if (mHeapId == -1) { mRealHeap = true; - mBase = mmap(0, size, access, MAP_SHARED, fd, 0); + mBase = mmap(0, size, access, MAP_SHARED, fd, offset); if (mBase == MAP_FAILED) { LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)", asBinder().get(), size, fd, strerror(errno)); @@ -317,6 +321,7 @@ void BpMemoryHeap::assertReallyMapped() const } else { mSize = size; mFlags = flags; + mOffset = offset; android_atomic_write(fd, &mHeapId); } } @@ -343,14 +348,19 @@ uint32_t BpMemoryHeap::getFlags() const { return mFlags; } +uint32_t BpMemoryHeap::getOffset() const { + assertMapped(); + return mOffset; +} + // --------------------------------------------------------------------------- IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap"); -BnMemoryHeap::BnMemoryHeap() { +BnMemoryHeap::BnMemoryHeap() { } -BnMemoryHeap::~BnMemoryHeap() { +BnMemoryHeap::~BnMemoryHeap() { } status_t BnMemoryHeap::onTransact( @@ -362,6 +372,7 @@ status_t BnMemoryHeap::onTransact( reply->writeFileDescriptor(getHeapID()); reply->writeInt32(getSize()); reply->writeInt32(getFlags()); + reply->writeInt32(getOffset()); return NO_ERROR; } break; default: @@ -383,17 +394,17 @@ HeapCache::~HeapCache() void HeapCache::binderDied(const wp<IBinder>& binder) { //LOGD("binderDied binder=%p", binder.unsafe_get()); - free_heap(binder); + free_heap(binder); } -sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) +sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) { Mutex::Autolock _l(mHeapCacheLock); ssize_t i = mHeapCache.indexOfKey(binder); if (i>=0) { heap_info_t& info = mHeapCache.editValueAt(i); LOGD_IF(VERBOSE, - "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", + "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, @@ -415,7 +426,7 @@ void HeapCache::free_heap(const sp<IBinder>& binder) { free_heap( wp<IBinder>(binder) ); } -void HeapCache::free_heap(const wp<IBinder>& binder) +void HeapCache::free_heap(const wp<IBinder>& binder) { sp<IMemoryHeap> rel; { @@ -426,7 +437,7 @@ void HeapCache::free_heap(const wp<IBinder>& binder) int32_t c = android_atomic_dec(&info.count); if (c == 1) { LOGD_IF(VERBOSE, - "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", + "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", binder.unsafe_get(), info.heap.get(), static_cast<BpMemoryHeap*>(info.heap.get())->mSize, static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, @@ -450,7 +461,7 @@ sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder) return realHeap; } -void HeapCache::dump_heaps() +void HeapCache::dump_heaps() { Mutex::Autolock _l(mHeapCacheLock); int c = mHeapCache.size(); @@ -459,7 +470,7 @@ void HeapCache::dump_heaps() BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get())); LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)", mHeapCache.keyAt(i).unsafe_get(), - info.heap.get(), info.count, + info.heap.get(), info.count, h->mHeapId, h->mBase, h->mSize); } } diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp index 9f501e2..bf4a73f 100644 --- a/libs/binder/MemoryHeapBase.cpp +++ b/libs/binder/MemoryHeapBase.cpp @@ -40,15 +40,15 @@ namespace android { // --------------------------------------------------------------------------- -MemoryHeapBase::MemoryHeapBase() +MemoryHeapBase::MemoryHeapBase() : mFD(-1), mSize(0), mBase(MAP_FAILED), - mDevice(NULL), mNeedUnmap(false) + mDevice(NULL), mNeedUnmap(false), mOffset(0) { } MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) + mDevice(0), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); @@ -65,7 +65,7 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) + mDevice(0), mNeedUnmap(false), mOffset(0) { int open_flags = O_RDWR; if (flags & NO_CACHING) @@ -84,7 +84,7 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) + mDevice(0), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); @@ -141,6 +141,7 @@ status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset) } mFD = fd; mSize = size; + mOffset = offset; return NO_ERROR; } @@ -183,5 +184,9 @@ const char* MemoryHeapBase::getDevice() const { return mDevice; } +uint32_t MemoryHeapBase::getOffset() const { + return mOffset; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp deleted file mode 100644 index fd8fe69..0000000 --- a/libs/binder/Permission.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ - -#include <stdint.h> -#include <utils/Log.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/Permission.h> - -namespace android { -// --------------------------------------------------------------------------- - -Permission::Permission(char const* name) - : mPermissionName(name), mPid(getpid()) -{ -} - -Permission::Permission(const String16& name) - : mPermissionName(name), mPid(getpid()) -{ -} - -Permission::Permission(const Permission& rhs) - : mPermissionName(rhs.mPermissionName), - mGranted(rhs.mGranted), - mPid(rhs.mPid) -{ -} - -Permission::~Permission() -{ -} - -bool Permission::operator < (const Permission& rhs) const -{ - return mPermissionName < rhs.mPermissionName; -} - -bool Permission::checkCalling() const -{ - IPCThreadState* ipcState = IPCThreadState::self(); - pid_t pid = ipcState->getCallingPid(); - uid_t uid = ipcState->getCallingUid(); - return doCheckPermission(pid, uid); -} - -bool Permission::check(pid_t pid, uid_t uid) const -{ - return doCheckPermission(pid, uid); -} - -bool Permission::doCheckPermission(pid_t pid, uid_t uid) const -{ - if ((uid == 0) || (pid == mPid)) { - // root and ourselves is always okay - return true; - } else { - // see if we already granted this permission for this uid - Mutex::Autolock _l(mLock); - if (mGranted.indexOf(uid) >= 0) - return true; - } - - bool granted = checkPermission(mPermissionName, pid, uid); - if (granted) { - Mutex::Autolock _l(mLock); - // no need to check again, the old item will be replaced if it is - // already there. - mGranted.add(uid); - } - return granted; -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp new file mode 100644 index 0000000..7278187 --- /dev/null +++ b/libs/binder/PermissionCache.cpp @@ -0,0 +1,113 @@ +/* + * 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 "PermissionCache" + +#include <stdint.h> +#include <utils/Log.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> +#include <utils/String8.h> + +namespace android { + +// ---------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ; + +// ---------------------------------------------------------------------------- + +PermissionCache::PermissionCache() { +} + +status_t PermissionCache::check(bool* granted, + const String16& permission, uid_t uid) const { + Mutex::Autolock _l(mLock); + Entry e; + e.name = permission; + e.uid = uid; + ssize_t index = mCache.indexOf(e); + if (index >= 0) { + *granted = mCache.itemAt(index).granted; + return NO_ERROR; + } + return NAME_NOT_FOUND; +} + +void PermissionCache::cache(const String16& permission, + uid_t uid, bool granted) { + Mutex::Autolock _l(mLock); + Entry e; + ssize_t index = mPermissionNamesPool.indexOf(permission); + if (index > 0) { + e.name = mPermissionNamesPool.itemAt(index); + } else { + mPermissionNamesPool.add(permission); + e.name = permission; + } + // note, we don't need to store the pid, which is not actually used in + // permission checks + e.uid = uid; + e.granted = granted; + index = mCache.indexOf(e); + if (index < 0) { + mCache.add(e); + } +} + +void PermissionCache::purge() { + Mutex::Autolock _l(mLock); + mCache.clear(); +} + +bool PermissionCache::checkCallingPermission(const String16& permission) { + return PermissionCache::checkCallingPermission(permission, NULL, NULL); +} + +bool PermissionCache::checkCallingPermission( + const String16& permission, int32_t* outPid, int32_t* outUid) { + IPCThreadState* ipcState = IPCThreadState::self(); + pid_t pid = ipcState->getCallingPid(); + uid_t uid = ipcState->getCallingUid(); + if (outPid) *outPid = pid; + if (outUid) *outUid = uid; + return PermissionCache::checkPermission(permission, pid, uid); +} + +bool PermissionCache::checkPermission( + const String16& permission, pid_t pid, uid_t uid) { + if ((uid == 0) || (pid == getpid())) { + // root and ourselves is always okay + return true; + } + + PermissionCache& pc(PermissionCache::getInstance()); + bool granted = false; + if (pc.check(&granted, permission, uid) != NO_ERROR) { + nsecs_t t = -systemTime(); + granted = android::checkPermission(permission, pid, uid); + t += systemTime(); + LOGD("checking %s for uid=%d => %s (%d us)", + String8(permission).string(), uid, + granted?"granted":"denied", (int)ns2us(t)); + pc.cache(permission, uid, granted); + } + return granted; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index 0cd51da..30f8d00 100644 --- a/libs/gui/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -43,7 +43,7 @@ public: } virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage) { + PixelFormat format, uint32_t usage, status_t* error) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); data.writeInt32(w); @@ -52,14 +52,15 @@ public: data.writeInt32(usage); remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); sp<GraphicBuffer> graphicBuffer; - bool nonNull = (bool)reply.readInt32(); - if (nonNull) { + status_t result = reply.readInt32(); + if (result == NO_ERROR) { graphicBuffer = new GraphicBuffer(); reply.read(*graphicBuffer); // reply.readStrongBinder(); // here we don't even have to read the BufferReference from // the parcel, it'll die with the parcel. } + *error = result; return graphicBuffer; } }; @@ -91,8 +92,10 @@ status_t BnGraphicBufferAlloc::onTransact( uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t usage = data.readInt32(); - sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage)); - reply->writeInt32(result != 0); + status_t error; + sp<GraphicBuffer> result = + createGraphicBuffer(w, h, format, usage, &error); + reply->writeInt32(error); if (result != 0) { reply->write(*result); // We add a BufferReference to this parcel to make sure the diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 40450a3..c1156d5 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -25,6 +25,8 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <private/surfaceflinger/LayerState.h> + #include <surfaceflinger/ISurfaceComposer.h> #include <ui/DisplayInfo.h> @@ -74,18 +76,17 @@ public: return interface_cast<IMemoryHeap>(reply.readStrongBinder()); } - virtual void openGlobalTransaction() + virtual void setTransactionState(const Vector<ComposerState>& state) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply); - } - - virtual void closeGlobalTransaction() - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply); + Vector<ComposerState>::const_iterator b(state.begin()); + Vector<ComposerState>::const_iterator e(state.end()); + data.writeInt32(state.size()); + for ( ; b != e ; ++b ) { + b->write(data); + } + remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) @@ -218,13 +219,17 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> b = createGraphicBufferAlloc()->asBinder(); reply->writeStrongBinder(b); } break; - case OPEN_GLOBAL_TRANSACTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - openGlobalTransaction(); - } break; - case CLOSE_GLOBAL_TRANSACTION: { + case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - closeGlobalTransaction(); + size_t count = data.readInt32(); + ComposerState s; + Vector<ComposerState> state; + state.setCapacity(count); + for (size_t i=0 ; i<count ; i++) { + s.read(data); + state.add(s); + } + setTransactionState(state); } break; case SET_ORIENTATION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 8d83392..bc97cac 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -51,8 +51,7 @@ namespace android { enum { CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, - DESTROY_SURFACE, - SET_STATE + DESTROY_SURFACE }; class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient> @@ -92,17 +91,6 @@ public: remote()->transact(DESTROY_SURFACE, data, &reply); return reply.readInt32(); } - - virtual status_t setState(int32_t count, const layer_state_t* states) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeInt32(count); - for (int i=0 ; i<count ; i++) - states[i].write(data); - remote()->transact(SET_STATE, data, &reply); - return reply.readInt32(); - } }; IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); @@ -133,17 +121,6 @@ status_t BnSurfaceComposerClient::onTransact( reply->writeInt32( destroySurface( data.readInt32() ) ); return NO_ERROR; } break; - case SET_STATE: { - CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - int32_t count = data.readInt32(); - layer_state_t* states = new layer_state_t[count]; - for (int i=0 ; i<count ; i++) - states[i].read(data); - status_t err = setState(count, states); - delete [] states; - reply->writeInt32(err); - return NO_ERROR; - } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 01c4c7e..87901e8 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -17,6 +17,7 @@ #include <utils/Errors.h> #include <binder/Parcel.h> #include <private/surfaceflinger/LayerState.h> +#include <surfaceflinger/ISurfaceComposerClient.h> namespace android { @@ -58,4 +59,14 @@ status_t layer_state_t::read(const Parcel& input) return NO_ERROR; } +status_t ComposerState::write(Parcel& output) const { + output.writeStrongBinder(client->asBinder()); + return state.write(output); +} + +status_t ComposerState::read(const Parcel& input) { + client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder()); + return state.read(input); +} + }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 4d1d923..9185e1e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -421,6 +421,10 @@ status_t Surface::validate(bool inCancelBuffer) const return NO_ERROR; } +sp<ISurfaceTexture> Surface::getSurfaceTexture() { + return mSurface != NULL ? mSurface->getSurfaceTexture() : NULL; +} + sp<IBinder> Surface::asBinder() const { return mSurface!=0 ? mSurface->asBinder() : 0; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1678711..8cead80 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -74,75 +74,52 @@ static inline surface_flinger_cblk_t const volatile * get_cblk() { // --------------------------------------------------------------------------- +// NOTE: this is NOT a member function (it's a friend defined with its +// declaration). +static inline +int compare_type( const ComposerState& lhs, const ComposerState& rhs) { + if (lhs.client < rhs.client) return -1; + if (lhs.client > rhs.client) return 1; + if (lhs.state.surface < rhs.state.surface) return -1; + if (lhs.state.surface > rhs.state.surface) return 1; + return 0; +} + class Composer : public Singleton<Composer> { - Mutex mLock; - SortedVector< wp<SurfaceComposerClient> > mActiveConnections; - SortedVector<sp<SurfaceComposerClient> > mOpenTransactions; + friend class Singleton<Composer>; - Composer() : Singleton<Composer>() { - } + mutable Mutex mLock; + SortedVector<ComposerState> mStates; - void addClientImpl(const sp<SurfaceComposerClient>& client) { - Mutex::Autolock _l(mLock); - mActiveConnections.add(client); - } + Composer() : Singleton<Composer>() { } - void removeClientImpl(const sp<SurfaceComposerClient>& client) { - Mutex::Autolock _l(mLock); - mActiveConnections.remove(client); - } + void closeGlobalTransactionImpl(); - void openGlobalTransactionImpl() - { - Mutex::Autolock _l(mLock); - if (mOpenTransactions.size()) { - LOGE("openGlobalTransaction() called more than once. skipping."); - return; - } - const size_t N = mActiveConnections.size(); - for (size_t i=0; i<N; i++) { - sp<SurfaceComposerClient> client(mActiveConnections[i].promote()); - if (client != 0 && mOpenTransactions.indexOf(client) < 0) { - if (client->openTransaction() == NO_ERROR) { - mOpenTransactions.add(client); - } else { - LOGE("openTransaction on client %p failed", client.get()); - // let it go, it'll fail later when the user - // tries to do something with the transaction - } - } - } - } + layer_state_t* getLayerStateLocked( + const sp<SurfaceComposerClient>& client, SurfaceID id); - void closeGlobalTransactionImpl() - { - mLock.lock(); - SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions); - mOpenTransactions.clear(); - mLock.unlock(); - - sp<ISurfaceComposer> sm(getComposerService()); - sm->openGlobalTransaction(); - const size_t N = clients.size(); - for (size_t i=0; i<N; i++) { - clients[i]->closeTransaction(); - } - sm->closeGlobalTransaction(); - } +public: - friend class Singleton<Composer>; + status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id, + int32_t x, int32_t y); + status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id, + uint32_t w, uint32_t h); + status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id, + int32_t z); + status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id, + uint32_t flags, uint32_t mask); + status_t setTransparentRegionHint( + const sp<SurfaceComposerClient>& client, SurfaceID id, + const Region& transparentRegion); + status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id, + float alpha); + status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id, + float dsdx, float dtdx, float dsdy, float dtdy); + status_t setFreezeTint( + const sp<SurfaceComposerClient>& client, SurfaceID id, + uint32_t tint); -public: - static void addClient(const sp<SurfaceComposerClient>& client) { - Composer::getInstance().addClientImpl(client); - } - static void removeClient(const sp<SurfaceComposerClient>& client) { - Composer::getInstance().removeClientImpl(client); - } - static void openGlobalTransaction() { - Composer::getInstance().openGlobalTransactionImpl(); - } static void closeGlobalTransaction() { Composer::getInstance().closeGlobalTransactionImpl(); } @@ -152,127 +129,185 @@ ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- -static inline int compare_type( const layer_state_t& lhs, - const layer_state_t& rhs) { - if (lhs.surface < rhs.surface) return -1; - if (lhs.surface > rhs.surface) return 1; - return 0; +void Composer::closeGlobalTransactionImpl() { + sp<ISurfaceComposer> sm(getComposerService()); + + Vector<ComposerState> transaction; + + { // scope for the lock + Mutex::Autolock _l(mLock); + transaction = mStates; + mStates.clear(); + } + + sm->setTransactionState(transaction); +} + +layer_state_t* Composer::getLayerStateLocked( + const sp<SurfaceComposerClient>& client, SurfaceID id) { + + ComposerState s; + s.client = client->mClient; + s.state.surface = id; + + ssize_t index = mStates.indexOf(s); + if (index < 0) { + // we don't have it, add an initialized layer_state to our list + index = mStates.add(s); + } + + ComposerState* const out = mStates.editArray(); + return &(out[index].state); +} + +status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, + SurfaceID id, int32_t x, int32_t y) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::ePositionChanged; + s->x = x; + s->y = y; + return NO_ERROR; +} + +status_t Composer::setSize(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t w, uint32_t h) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eSizeChanged; + s->w = w; + s->h = h; + return NO_ERROR; +} + +status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, + SurfaceID id, int32_t z) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eLayerChanged; + s->z = z; + return NO_ERROR; +} + +status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t flags, + uint32_t mask) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eVisibilityChanged; + s->flags &= ~mask; + s->flags |= (flags & mask); + s->mask |= mask; + return NO_ERROR; +} + +status_t Composer::setTransparentRegionHint( + const sp<SurfaceComposerClient>& client, SurfaceID id, + const Region& transparentRegion) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eTransparentRegionChanged; + s->transparentRegion = transparentRegion; + return NO_ERROR; +} + +status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, + SurfaceID id, float alpha) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eAlphaChanged; + s->alpha = alpha; + return NO_ERROR; +} + +status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, + SurfaceID id, float dsdx, float dtdx, + float dsdy, float dtdy) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eMatrixChanged; + layer_state_t::matrix22_t matrix; + matrix.dsdx = dsdx; + matrix.dtdx = dtdx; + matrix.dsdy = dsdy; + matrix.dtdy = dtdy; + s->matrix = matrix; + return NO_ERROR; } +status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client, + SurfaceID id, uint32_t tint) { + Mutex::Autolock _l(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) + return BAD_INDEX; + s->what |= ISurfaceComposer::eFreezeTintChanged; + s->tint = tint; + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + SurfaceComposerClient::SurfaceComposerClient() - : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT) + : mStatus(NO_INIT), mComposer(Composer::getInstance()) { } -void SurfaceComposerClient::onFirstRef() -{ +void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sm(getComposerService()); if (sm != 0) { sp<ISurfaceComposerClient> conn = sm->createConnection(); if (conn != 0) { mClient = conn; - Composer::addClient(this); - mPrebuiltLayerState = new layer_state_t; mStatus = NO_ERROR; } } } -SurfaceComposerClient::~SurfaceComposerClient() -{ - delete mPrebuiltLayerState; +SurfaceComposerClient::~SurfaceComposerClient() { dispose(); } -status_t SurfaceComposerClient::initCheck() const -{ +status_t SurfaceComposerClient::initCheck() const { return mStatus; } -sp<IBinder> SurfaceComposerClient::connection() const -{ +sp<IBinder> SurfaceComposerClient::connection() const { return (mClient != 0) ? mClient->asBinder() : 0; } status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, - void* cookie, uint32_t flags) -{ + void* cookie, uint32_t flags) { sp<ISurfaceComposer> sm(getComposerService()); return sm->asBinder()->linkToDeath(recipient, cookie, flags); } -void SurfaceComposerClient::dispose() -{ +void SurfaceComposerClient::dispose() { // this can be called more than once. sp<ISurfaceComposerClient> client; Mutex::Autolock _lm(mLock); if (mClient != 0) { - Composer::removeClient(this); client = mClient; // hold ref while lock is held mClient.clear(); } mStatus = NO_INIT; } -status_t SurfaceComposerClient::getDisplayInfo( - DisplayID dpy, DisplayInfo* info) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - - info->w = dcblk->w; - info->h = dcblk->h; - info->orientation = dcblk->orientation; - info->xdpi = dcblk->xdpi; - info->ydpi = dcblk->ydpi; - info->fps = dcblk->fps; - info->density = dcblk->density; - return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); -} - -ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - return dcblk->w; -} - -ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - return dcblk->h; -} - -ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) -{ - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) - return BAD_VALUE; - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - volatile display_cblk_t const * dcblk = cblk->displays + dpy; - return dcblk->orientation; -} - -ssize_t SurfaceComposerClient::getNumberOfDisplays() -{ - volatile surface_flinger_cblk_t const * cblk = get_cblk(); - uint32_t connected = cblk->connected; - int n = 0; - while (connected) { - if (connected&1) n++; - connected >>= 1; - } - return n; -} - sp<SurfaceControl> SurfaceComposerClient::createSurface( DisplayID display, uint32_t w, @@ -310,237 +345,167 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( return result; } -status_t SurfaceComposerClient::destroySurface(SurfaceID sid) -{ +status_t SurfaceComposerClient::destroySurface(SurfaceID sid) { if (mStatus != NO_ERROR) return mStatus; - - // it's okay to destroy a surface while a transaction is open, - // (transactions really are a client-side concept) - // however, this indicates probably a misuse of the API or a bug - // in the client code. - LOGW_IF(mTransactionOpen, - "Destroying surface while a transaction is open. " - "Client %p: destroying surface %d, mTransactionOpen=%d", - this, sid, mTransactionOpen); - status_t err = mClient->destroySurface(sid); return err; } -void SurfaceComposerClient::openGlobalTransaction() -{ - Composer::openGlobalTransaction(); +inline Composer& SurfaceComposerClient::getComposer() { + return mComposer; } -void SurfaceComposerClient::closeGlobalTransaction() -{ - Composer::closeGlobalTransaction(); -} +// ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) -{ - sp<ISurfaceComposer> sm(getComposerService()); - return sm->freezeDisplay(dpy, flags); +void SurfaceComposerClient::openGlobalTransaction() { + // Currently a no-op } -status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) -{ - sp<ISurfaceComposer> sm(getComposerService()); - return sm->unfreezeDisplay(dpy, flags); +void SurfaceComposerClient::closeGlobalTransaction() { + Composer::closeGlobalTransaction(); } -int SurfaceComposerClient::setOrientation(DisplayID dpy, - int orientation, uint32_t flags) -{ - sp<ISurfaceComposer> sm(getComposerService()); - return sm->setOrientation(dpy, orientation, flags); -} +// ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::openTransaction() -{ - if (mStatus != NO_ERROR) - return mStatus; - Mutex::Autolock _l(mLock); - mTransactionOpen++; - return NO_ERROR; +status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { + return getComposer().setFreezeTint(this, id, tint); } -status_t SurfaceComposerClient::closeTransaction() -{ - if (mStatus != NO_ERROR) - return mStatus; - - Mutex::Autolock _l(mLock); - if (mTransactionOpen <= 0) { - LOGE( "closeTransaction (client %p, mTransactionOpen=%d) " - "called more times than openTransaction()", - this, mTransactionOpen); - return INVALID_OPERATION; - } +status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) { + return getComposer().setPosition(this, id, x, y); +} - if (mTransactionOpen >= 2) { - mTransactionOpen--; - return NO_ERROR; - } +status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) { + return getComposer().setSize(this, id, w, h); +} - mTransactionOpen = 0; - const ssize_t count = mStates.size(); - if (count) { - mClient->setState(count, mStates.array()); - mStates.clear(); - } - return NO_ERROR; +status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { + return getComposer().setLayer(this, id, z); } -layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index) -{ - // API usage error, do nothing. - if (mTransactionOpen<=0) { - LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d", - this, int(index), mTransactionOpen); - return 0; - } +status_t SurfaceComposerClient::hide(SurfaceID id) { + return getComposer().setFlags(this, id, + ISurfaceComposer::eLayerHidden, + ISurfaceComposer::eLayerHidden); +} - // use mPrebuiltLayerState just to find out if we already have it - layer_state_t& dummy(*mPrebuiltLayerState); - dummy.surface = index; - ssize_t i = mStates.indexOf(dummy); - if (i < 0) { - // we don't have it, add an initialized layer_state to our list - i = mStates.add(dummy); - } - return mStates.editArray() + i; +status_t SurfaceComposerClient::show(SurfaceID id, int32_t) { + return getComposer().setFlags(this, id, + 0, + ISurfaceComposer::eLayerHidden); } -layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id) -{ - layer_state_t* s; - mLock.lock(); - s = get_state_l(id); - if (!s) mLock.unlock(); - return s; +status_t SurfaceComposerClient::freeze(SurfaceID id) { + return getComposer().setFlags(this, id, + ISurfaceComposer::eLayerFrozen, + ISurfaceComposer::eLayerFrozen); } -void SurfaceComposerClient::unlockLayerState() -{ - mLock.unlock(); +status_t SurfaceComposerClient::unfreeze(SurfaceID id) { + return getComposer().setFlags(this, id, + 0, + ISurfaceComposer::eLayerFrozen); } -status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) -{ - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::ePositionChanged; - s->x = x; - s->y = y; - unlockLayerState(); - return NO_ERROR; +status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, + uint32_t mask) { + return getComposer().setFlags(this, id, flags, mask); } -status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) -{ - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eSizeChanged; - s->w = w; - s->h = h; - unlockLayerState(); - return NO_ERROR; +status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id, + const Region& transparentRegion) { + return getComposer().setTransparentRegionHint(this, id, transparentRegion); } -status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) -{ - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eLayerChanged; - s->z = z; - unlockLayerState(); - return NO_ERROR; +status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { + return getComposer().setAlpha(this, id, alpha); } -status_t SurfaceComposerClient::hide(SurfaceID id) -{ - return setFlags(id, ISurfaceComposer::eLayerHidden, - ISurfaceComposer::eLayerHidden); +status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx, + float dsdy, float dtdy) { + return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy); } -status_t SurfaceComposerClient::show(SurfaceID id, int32_t) +// ---------------------------------------------------------------------------- + +status_t SurfaceComposerClient::getDisplayInfo( + DisplayID dpy, DisplayInfo* info) { - return setFlags(id, 0, ISurfaceComposer::eLayerHidden); + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + + info->w = dcblk->w; + info->h = dcblk->h; + info->orientation = dcblk->orientation; + info->xdpi = dcblk->xdpi; + info->ydpi = dcblk->ydpi; + info->fps = dcblk->fps; + info->density = dcblk->density; + return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); } -status_t SurfaceComposerClient::freeze(SurfaceID id) +ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) { - return setFlags(id, ISurfaceComposer::eLayerFrozen, - ISurfaceComposer::eLayerFrozen); + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->w; } -status_t SurfaceComposerClient::unfreeze(SurfaceID id) +ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) { - return setFlags(id, 0, ISurfaceComposer::eLayerFrozen); + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->h; } -status_t SurfaceComposerClient::setFlags(SurfaceID id, - uint32_t flags, uint32_t mask) +ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eVisibilityChanged; - s->flags &= ~mask; - s->flags |= (flags & mask); - s->mask |= mask; - unlockLayerState(); - return NO_ERROR; + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->orientation; } -status_t SurfaceComposerClient::setTransparentRegionHint( - SurfaceID id, const Region& transparentRegion) +ssize_t SurfaceComposerClient::getNumberOfDisplays() { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eTransparentRegionChanged; - s->transparentRegion = transparentRegion; - unlockLayerState(); - return NO_ERROR; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + uint32_t connected = cblk->connected; + int n = 0; + while (connected) { + if (connected&1) n++; + connected >>= 1; + } + return n; } -status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) +// ---------------------------------------------------------------------------- + +status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eAlphaChanged; - s->alpha = alpha; - unlockLayerState(); - return NO_ERROR; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->freezeDisplay(dpy, flags); } -status_t SurfaceComposerClient::setMatrix( - SurfaceID id, - float dsdx, float dtdx, - float dsdy, float dtdy ) +status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eMatrixChanged; - layer_state_t::matrix22_t matrix; - matrix.dsdx = dsdx; - matrix.dtdx = dtdx; - matrix.dsdy = dsdy; - matrix.dtdy = dtdy; - s->matrix = matrix; - unlockLayerState(); - return NO_ERROR; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->unfreezeDisplay(dpy, flags); } -status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) +int SurfaceComposerClient::setOrientation(DisplayID dpy, + int orientation, uint32_t flags) { - layer_state_t* s = lockLayerState(id); - if (!s) return BAD_INDEX; - s->what |= ISurfaceComposer::eFreezeTintChanged; - s->tint = tint; - unlockLayerState(); - return NO_ERROR; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->setOrientation(dpy, orientation, flags); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 3cecdb4..886a3fb 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -78,7 +78,7 @@ static float mtxRot270[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); -SurfaceTexture::SurfaceTexture(GLuint tex) : +SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) : mDefaultWidth(1), mDefaultHeight(1), mPixelFormat(PIXEL_FORMAT_RGBA_8888), @@ -91,7 +91,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex) : mCurrentTimestamp(0), mNextTransform(0), mTexName(tex), - mSynchronousMode(false) { + mSynchronousMode(false), + mAllowSynchronousMode(allowSynchronousMode) { LOGV("SurfaceTexture::SurfaceTexture"); sp<ISurfaceComposer> composer(ComposerService::getComposerService()); mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); @@ -147,6 +148,11 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGV("SurfaceTexture::setBufferCount"); Mutex::Autolock lock(mMutex); + if (bufferCount > NUM_BUFFER_SLOTS) { + LOGE("setBufferCount: bufferCount larger than slots available"); + return BAD_VALUE; + } + // Error out if the user has dequeued buffers for (int i=0 ; i<mBufferCount ; i++) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { @@ -207,7 +213,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("SurfaceTexture::dequeueBuffer"); - if ((w && !h) || (!w & h)) { + if ((w && !h) || (!w && h)) { LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } @@ -346,11 +352,13 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, ((uint32_t(buffer->usage) & usage) != usage)) { usage |= GraphicBuffer::USAGE_HW_TEXTURE; + status_t error; sp<GraphicBuffer> graphicBuffer( - mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); + mGraphicBufferAlloc->createGraphicBuffer( + w, h, format, usage, &error)); if (graphicBuffer == 0) { LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed"); - return NO_MEMORY; + return error; } if (updateFormat) { mPixelFormat = format; @@ -371,6 +379,9 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) { Mutex::Autolock lock(mMutex); status_t err = OK; + if (!mAllowSynchronousMode && enabled) + return err; + if (!enabled) { // going to asynchronous mode, drain the queue while (mSynchronousMode != enabled && !mQueue.isEmpty()) { @@ -413,17 +424,22 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { return -EINVAL; } - if (mQueue.empty()) { - listener = mFrameAvailableListener; - } - if (mSynchronousMode) { - // in synchronous mode we queue all buffers in a FIFO + // In synchronous mode we queue all buffers in a FIFO. mQueue.push_back(buf); + + // Synchronous mode always signals that an additional frame should + // be consumed. + listener = mFrameAvailableListener; } else { - // in asynchronous mode we only keep the most recent buffer + // In asynchronous mode we only keep the most recent buffer. if (mQueue.empty()) { mQueue.push_back(buf); + + // Asynchronous mode only signals that a frame should be + // consumed if no previous frame was pending. If a frame were + // pending then the consumer would have already been notified. + listener = mFrameAvailableListener; } else { Fifo::iterator front(mQueue.begin()); // buffer currently queued is freed @@ -479,24 +495,14 @@ status_t SurfaceTexture::setTransform(uint32_t transform) { status_t SurfaceTexture::updateTexImage() { LOGV("SurfaceTexture::updateTexImage"); - Mutex::Autolock lock(mMutex); - int buf = mCurrentTexture; + // In asynchronous mode the list is guaranteed to be one buffer + // deep, while in synchronous mode we use the oldest buffer. if (!mQueue.empty()) { - // in asynchronous mode the list is guaranteed to be one buffer deep, - // while in synchronous mode we use the oldest buffer Fifo::iterator front(mQueue.begin()); - buf = *front; - mQueue.erase(front); - if (mQueue.isEmpty()) { - mDequeueCondition.signal(); - } - } + int buf = *front; - // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT, - // so this check will fail until a buffer gets queued. - if (mCurrentTexture != buf) { // Update the GL texture object. EGLImageKHR image = mSlots[buf].mEglImage; if (image == EGL_NO_IMAGE_KHR) { @@ -534,7 +540,7 @@ status_t SurfaceTexture::updateTexImage() { } if (mCurrentTexture != INVALID_BUFFER_SLOT) { - // the current buffer becomes FREE if it was still in the queued + // The current buffer becomes FREE if it was still in the queued // state. If it has already been given to the client // (synchronous mode), then it stays in DEQUEUED state. if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) @@ -549,17 +555,17 @@ status_t SurfaceTexture::updateTexImage() { mCurrentTransform = mSlots[buf].mTransform; mCurrentTimestamp = mSlots[buf].mTimestamp; computeCurrentTransformMatrix(); + + // Now that we've passed the point at which failures can happen, + // it's safe to remove the buffer from the front of the queue. + mQueue.erase(front); mDequeueCondition.signal(); } else { // We always bind the texture even if we don't update its contents. glBindTexture(mCurrentTextureTarget, mTexName); } - return OK; -} -size_t SurfaceTexture::getQueuedCount() const { - Mutex::Autolock lock(mMutex); - return mQueue.size(); + return OK; } bool SurfaceTexture::isExternalFormat(uint32_t format) @@ -700,10 +706,10 @@ nsecs_t SurfaceTexture::getTimestamp() { } void SurfaceTexture::setFrameAvailableListener( - const sp<FrameAvailableListener>& l) { + const sp<FrameAvailableListener>& listener) { LOGV("SurfaceTexture::setFrameAvailableListener"); Mutex::Autolock lock(mMutex); - mFrameAvailableListener = l; + mFrameAvailableListener = listener; } sp<IBinder> SurfaceTexture::getAllocator() { diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index f219639..c06400e 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -84,10 +84,10 @@ protected: ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction()); + SurfaceComposerClient::openGlobalTransaction(); ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction()); + SurfaceComposerClient::closeGlobalTransaction(); sp<ANativeWindow> window = mSurfaceControl->getSurface(); mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, @@ -419,6 +419,31 @@ protected: ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); } + class FrameWaiter : public SurfaceTexture::FrameAvailableListener { + public: + FrameWaiter(): + mPendingFrames(0) { + } + + void waitForFrame() { + Mutex::Autolock lock(mMutex); + while (mPendingFrames == 0) { + mCondition.wait(mMutex); + } + mPendingFrames--; + } + + virtual void onFrameAvailable() { + Mutex::Autolock lock(mMutex); + mPendingFrames++; + mCondition.signal(); + } + + int mPendingFrames; + Mutex mMutex; + Condition mCondition; + }; + sp<SurfaceTexture> mST; sp<SurfaceTextureClient> mSTC; sp<ANativeWindow> mANW; @@ -648,6 +673,157 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { } } +// This test is intended to catch synchronization bugs between the CPU-written +// and GPU-read buffers. +TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { + enum { texWidth = 16 }; + enum { texHeight = 16 }; + enum { numFrames = 1024 }; + + ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true)); + ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), + texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), + GRALLOC_USAGE_SW_WRITE_OFTEN)); + + struct TestPixel { + int x; + int y; + }; + const TestPixel testPixels[] = { + { 4, 11 }, + { 12, 14 }, + { 7, 2 }, + }; + enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])}; + + class ProducerThread : public Thread { + public: + ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels): + mANW(anw), + mTestPixels(testPixels) { + } + + virtual ~ProducerThread() { + } + + virtual bool threadLoop() { + for (int i = 0; i < numFrames; i++) { + ANativeWindowBuffer* anb; + if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) { + return false; + } + if (anb == NULL) { + return false; + } + + sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()) + != NO_ERROR) { + return false; + } + + const int yuvTexOffsetY = 0; + int stride = buf->getStride(); + int yuvTexStrideY = stride; + int yuvTexOffsetV = yuvTexStrideY * texHeight; + int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; + int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2; + int yuvTexStrideU = yuvTexStrideV; + + uint8_t* img = NULL; + buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + + // Gray out all the test pixels first, so we're more likely to + // see a failure if GL is still texturing from the buffer we + // just dequeued. + for (int j = 0; j < numTestPixels; j++) { + int x = mTestPixels[j].x; + int y = mTestPixels[j].y; + uint8_t value = 128; + img[y*stride + x] = value; + } + + // Fill the buffer with gray. + for (int y = 0; y < texHeight; y++) { + for (int x = 0; x < texWidth; x++) { + img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128; + img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128; + img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128; + } + } + + // Set the test pixels to either white or black. + for (int j = 0; j < numTestPixels; j++) { + int x = mTestPixels[j].x; + int y = mTestPixels[j].y; + uint8_t value = 0; + if (j == (i % numTestPixels)) { + value = 255; + } + img[y*stride + x] = value; + } + + buf->unlock(); + if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()) + != NO_ERROR) { + return false; + } + } + return false; + } + + sp<ANativeWindow> mANW; + const TestPixel* mTestPixels; + }; + + sp<FrameWaiter> fw(new FrameWaiter); + mST->setFrameAvailableListener(fw); + + sp<Thread> pt(new ProducerThread(mANW, testPixels)); + pt->run(); + + glViewport(0, 0, texWidth, texHeight); + + glClearColor(0.2, 0.2, 0.2, 0.2); + glClear(GL_COLOR_BUFFER_BIT); + + // We wait for the first two frames up front so that the producer will be + // likely to dequeue the buffer that's currently being textured from. + fw->waitForFrame(); + fw->waitForFrame(); + + for (int i = 0; i < numFrames; i++) { + SCOPED_TRACE(String8::format("frame %d", i).string()); + + // We must wait for each frame to come in because if we ever do an + // updateTexImage call that doesn't consume a newly available buffer + // then the producer and consumer will get out of sync, which will cause + // a deadlock. + if (i > 1) { + fw->waitForFrame(); + } + mST->updateTexImage(); + drawTexture(); + + for (int j = 0; j < numTestPixels; j++) { + int x = testPixels[j].x; + int y = testPixels[j].y; + uint8_t value = 0; + if (j == (i % numTestPixels)) { + // We must y-invert the texture coords + EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255)); + } else { + // We must y-invert the texture coords + EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255)); + } + } + } + + pt->requestExitAndWait(); +} + // XXX: This test is disabled because there are currently no drivers that can // handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target. TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 35c8640..ce587b3 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -31,15 +31,15 @@ protected: ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); mSurfaceControl = mComposerClient->createSurface( - String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0); + String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction()); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000)); + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction()); + SurfaceComposerClient::closeGlobalTransaction(); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); @@ -84,7 +84,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { PixelFormat fmt=0; sp<ISurfaceComposer> sf(ComposerService::getComposerService()); ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0, - 40000)); + 0x7fffffff)); ASSERT_TRUE(heap != NULL); // Set the PROTECTED usage bit and verify that the screenshot fails. Note @@ -94,6 +94,18 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { GRALLOC_USAGE_PROTECTED)); ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); ANativeWindowBuffer* buf = 0; + + status_t err = anw->dequeueBuffer(anw.get(), &buf); + if (err) { + // we could fail if GRALLOC_USAGE_PROTECTED is not supported. + // that's okay as long as this is the reason for the failure. + // try again without the GRALLOC_USAGE_PROTECTED bit. + ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0)); + ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); + return; + } + ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf)); + for (int i = 0; i < 4; i++) { // Loop to make sure SurfaceFlinger has retired a protected buffer. ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); @@ -103,7 +115,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { heap = 0; w = h = fmt = 0; ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt, - 64, 64, 0, 40000)); + 64, 64, 0, 0x7fffffff)); ASSERT_TRUE(heap == NULL); // XXX: This should not be needed, but it seems that the new buffers don't @@ -126,7 +138,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { heap = 0; w = h = fmt = 0; ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0, - 40000)); + 0x7fffffff)); ASSERT_TRUE(heap != NULL); } diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index f9990bb..427bbba 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -43,7 +43,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ $(commonSources) \ EGLUtils.cpp \ - EventRecurrence.cpp \ FramebufferNativeWindow.cpp \ GraphicBuffer.cpp \ GraphicBufferAllocator.cpp \ diff --git a/libs/ui/EventRecurrence.cpp b/libs/ui/EventRecurrence.cpp deleted file mode 100644 index b436b50..0000000 --- a/libs/ui/EventRecurrence.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - */ - -#include <pim/EventRecurrence.h> -#include <utils/String8.h> -#include <stdio.h> -#include <limits.h> - -namespace android { - -#define FAIL_HERE() do { \ - printf("Parsing failed at line %d\n", __LINE__); \ - return UNKNOWN_ERROR; \ - } while(0) - -EventRecurrence::EventRecurrence() - :freq((freq_t)0), - until(), - count(0), - interval(0), - bysecond(0), - bysecondCount(0), - byminute(0), - byminuteCount(0), - byhour(0), - byhourCount(0), - byday(0), - bydayNum(0), - bydayCount(0), - bymonthday(0), - bymonthdayCount(0), - byyearday(0), - byyeardayCount(0), - byweekno(0), - byweeknoCount(0), - bymonth(0), - bymonthCount(0), - bysetpos(0), - bysetposCount(0), - wkst(0) -{ -} - -EventRecurrence::~EventRecurrence() -{ - delete[] bysecond; - delete[] byminute; - delete[] byhour; - delete[] byday; - delete[] bydayNum; - delete[] byyearday; - delete[] bymonthday; - delete[] byweekno; - delete[] bymonth; - delete[] bysetpos; -} - -enum LHS { - NONE_LHS = 0, - FREQ, - UNTIL, - COUNT, - INTERVAL, - BYSECOND, - BYMINUTE, - BYHOUR, - BYDAY, - BYMONTHDAY, - BYYEARDAY, - BYWEEKNO, - BYMONTH, - BYSETPOS, - WKST -}; - -struct LHSProc -{ - const char16_t* text; - size_t textSize; - uint32_t value; -}; - -const char16_t FREQ_text[] = { 'F', 'R', 'E', 'Q' }; -const char16_t UNTIL_text[] = { 'U', 'N', 'T', 'I', 'L' }; -const char16_t COUNT_text[] = { 'C', 'O', 'U', 'N', 'T' }; -const char16_t INTERVAL_text[] = { 'I', 'N', 'T', 'E', 'R', 'V', 'A', 'L'}; -const char16_t BYSECOND_text[] = { 'B', 'Y', 'S', 'E', 'C', 'O', 'N', 'D' }; -const char16_t BYMINUTE_text[] = { 'B', 'Y', 'M', 'I', 'N', 'U', 'T', 'E' }; -const char16_t BYHOUR_text[] = { 'B', 'Y', 'H', 'O', 'U', 'R' }; -const char16_t BYDAY_text[] = { 'B', 'Y', 'D', 'A', 'Y' }; -const char16_t BYMONTHDAY_text[] = { 'B','Y','M','O','N','T','H','D','A','Y' }; -const char16_t BYYEARDAY_text[] = { 'B','Y','Y','E','A','R','D','A','Y' }; -const char16_t BYWEEKNO_text[] = { 'B', 'Y', 'W', 'E', 'E', 'K', 'N', 'O' }; -const char16_t BYMONTH_text[] = { 'B', 'Y', 'M', 'O', 'N', 'T', 'H' }; -const char16_t BYSETPOS_text[] = { 'B', 'Y', 'S', 'E', 'T', 'P', 'O', 'S' }; -const char16_t WKST_text[] = { 'W', 'K', 'S', 'T' }; - -#define SIZ(x) (sizeof(x)/sizeof(x[0])) - -const LHSProc LHSPROC[] = { - { FREQ_text, SIZ(FREQ_text), FREQ }, - { UNTIL_text, SIZ(UNTIL_text), UNTIL }, - { COUNT_text, SIZ(COUNT_text), COUNT }, - { INTERVAL_text, SIZ(INTERVAL_text), INTERVAL }, - { BYSECOND_text, SIZ(BYSECOND_text), BYSECOND }, - { BYMINUTE_text, SIZ(BYMINUTE_text), BYMINUTE }, - { BYHOUR_text, SIZ(BYHOUR_text), BYHOUR }, - { BYDAY_text, SIZ(BYDAY_text), BYDAY }, - { BYMONTHDAY_text, SIZ(BYMONTHDAY_text), BYMONTHDAY }, - { BYYEARDAY_text, SIZ(BYYEARDAY_text), BYYEARDAY }, - { BYWEEKNO_text, SIZ(BYWEEKNO_text), BYWEEKNO }, - { BYMONTH_text, SIZ(BYMONTH_text), BYMONTH }, - { BYSETPOS_text, SIZ(BYSETPOS_text), BYSETPOS }, - { WKST_text, SIZ(WKST_text), WKST }, - { NULL, 0, NONE_LHS }, -}; - -const char16_t SECONDLY_text[] = { 'S','E','C','O','N','D','L','Y' }; -const char16_t MINUTELY_text[] = { 'M','I','N','U','T','E','L','Y' }; -const char16_t HOURLY_text[] = { 'H','O','U','R','L','Y' }; -const char16_t DAILY_text[] = { 'D','A','I','L','Y' }; -const char16_t WEEKLY_text[] = { 'W','E','E','K','L','Y' }; -const char16_t MONTHLY_text[] = { 'M','O','N','T','H','L','Y' }; -const char16_t YEARLY_text[] = { 'Y','E','A','R','L','Y' }; - -typedef LHSProc FreqProc; - -const FreqProc FREQPROC[] = { - { SECONDLY_text, SIZ(SECONDLY_text), EventRecurrence::SECONDLY }, - { MINUTELY_text, SIZ(MINUTELY_text), EventRecurrence::MINUTELY }, - { HOURLY_text, SIZ(HOURLY_text), EventRecurrence::HOURLY }, - { DAILY_text, SIZ(DAILY_text), EventRecurrence::DAILY }, - { WEEKLY_text, SIZ(WEEKLY_text), EventRecurrence::WEEKLY }, - { MONTHLY_text, SIZ(MONTHLY_text), EventRecurrence::MONTHLY }, - { YEARLY_text, SIZ(YEARLY_text), EventRecurrence::YEARLY }, - { NULL, 0, NONE_LHS }, -}; - -const char16_t SU_text[] = { 'S','U' }; -const char16_t MO_text[] = { 'M','O' }; -const char16_t TU_text[] = { 'T','U' }; -const char16_t WE_text[] = { 'W','E' }; -const char16_t TH_text[] = { 'T','H' }; -const char16_t FR_text[] = { 'F','R' }; -const char16_t SA_text[] = { 'S','A' }; - -const FreqProc WEEKDAYPROC[] = { - { SU_text, SIZ(SU_text), EventRecurrence::SU }, - { MO_text, SIZ(MO_text), EventRecurrence::MO }, - { TU_text, SIZ(TU_text), EventRecurrence::TU }, - { WE_text, SIZ(WE_text), EventRecurrence::WE }, - { TH_text, SIZ(TH_text), EventRecurrence::TH }, - { FR_text, SIZ(FR_text), EventRecurrence::FR }, - { SA_text, SIZ(SA_text), EventRecurrence::SA }, - { NULL, 0, NONE_LHS }, -}; - -// returns the index into LHSPROC for the match or -1 if not found -inline static int -match_proc(const LHSProc* p, const char16_t* str, size_t len) -{ - int i = 0; - while (p->text != NULL) { - if (p->textSize == len) { - if (0 == memcmp(p->text, str, len*sizeof(char16_t))) { - return i; - } - } - p++; - i++; - } - return -1; -} - -// rangeMin and rangeMax are inclusive -static status_t -parse_int(const char16_t* str, size_t len, int* out, - int rangeMin, int rangeMax, bool zeroOK) -{ - char16_t c; - size_t i=0; - - if (len == 0) { - FAIL_HERE(); - } - bool negative = false; - c = str[0]; - if (c == '-' ) { - negative = true; - i++; - } - else if (c == '+') { - i++; - } - int n = 0; - for (; i<len; i++) { - c = str[i]; - if (c < '0' || c > '9') { - FAIL_HERE(); - } - int prev = n; - n *= 10; - // the spec doesn't address how big these numbers can be, - // so we're not going to worry about not being able to represent - // INT_MIN, and if we're going to wrap, we'll just clamp to - // INT_MAX instead - if (n < prev) { - n = INT_MAX; - } else { - n += c - '0'; - } - } - if (negative) { - n = -n; - } - if (n < rangeMin || n > rangeMax) { - FAIL_HERE(); - } - if (!zeroOK && n == 0) { - FAIL_HERE(); - } - *out = n; - return NO_ERROR; -} - -static status_t -parse_int_list(const char16_t* str, size_t len, int* countOut, int** listOut, - int rangeMin, int rangeMax, bool zeroOK, - status_t (*func)(const char16_t*,size_t,int*,int,int,bool)=parse_int) -{ - status_t err; - - if (len == 0) { - *countOut = 0; - *listOut = NULL; - return NO_ERROR; - } - - // make one pass through looking for commas so we know how big to make our - // out array. - int count = 1; - for (size_t i=0; i<len; i++) { - if (str[i] == ',') { - count++; - } - } - - int* list = new int[count]; - const char16_t* p = str; - int commaIndex = 0; - size_t i; - - for (i=0; i<len; i++) { - if (str[i] == ',') { - err = func(p, (str+i-p), list+commaIndex, rangeMin, - rangeMax, zeroOK); - if (err != NO_ERROR) { - goto bail; - } - commaIndex++; - p = str+i+1; - } - } - - err = func(p, (str+i-p), list+commaIndex, rangeMin, rangeMax, zeroOK); - if (err != NO_ERROR) { - goto bail; - } - commaIndex++; - - *countOut = count; - *listOut = list; - - return NO_ERROR; - -bail: - delete[] list; - FAIL_HERE(); -} - -// the numbers here are small, so we pack them both into one value, and then -// split it out later. it lets us reuse all the comma separated list code. -static status_t -parse_byday(const char16_t* s, size_t len, int* out, - int rangeMin, int rangeMax, bool zeroOK) -{ - status_t err; - int n = 0; - const char16_t* p = s; - size_t plen = len; - - if (len > 0) { - char16_t c = s[0]; - if (c == '-' || c == '+' || (c >= '0' && c <= '9')) { - if (len > 1) { - size_t nlen = 0; - c = s[nlen]; - while (nlen < len - && (c == '-' || c == '+' || (c >= '0' && c <= '9'))) { - c = s[nlen]; - nlen++; - } - if (nlen > 0) { - nlen--; - err = parse_int(s, nlen, &n, rangeMin, rangeMax, zeroOK); - if (err != NO_ERROR) { - FAIL_HERE(); - } - p += nlen; - plen -= nlen; - } - } - } - - int index = match_proc(WEEKDAYPROC, p, plen); - if (index >= 0) { - *out = (0xffff0000 & WEEKDAYPROC[index].value) - | (0x0000ffff & n); - return NO_ERROR; - } - } - return UNKNOWN_ERROR; -} - -static void -postprocess_byday(int count, int* byday, int** bydayNum) -{ - int* bdn = new int[count]; - *bydayNum = bdn; - for (int i=0; i<count; i++) { - uint32_t v = byday[i]; - int16_t num = v & 0x0000ffff; - byday[i] = v & 0xffff0000; - // will sign extend: - bdn[i] = num; - } -} - -#define PARSE_INT_LIST_CHECKED(name, rangeMin, rangeMax, zeroOK) \ - if (name##Count != 0 || NO_ERROR != parse_int_list(s, slen, \ - &name##Count, &name, rangeMin, rangeMax, zeroOK)) { \ - FAIL_HERE(); \ - } -status_t -EventRecurrence::parse(const String16& str) -{ - char16_t const* work = str.string(); - size_t len = str.size(); - - int lhsIndex = NONE_LHS; - int index; - - size_t start = 0; - for (size_t i=0; i<len; i++) { - char16_t c = work[i]; - if (c != ';' && i == len-1) { - c = ';'; - i++; - } - if (c == ';' || c == '=') { - if (i != start) { - const char16_t* s = work+start; - const size_t slen = i-start; - - String8 thestring(String16(s, slen)); - - switch (c) - { - case '=': - if (lhsIndex == NONE_LHS) { - lhsIndex = match_proc(LHSPROC, s, slen); - if (lhsIndex >= 0) { - break; - } - } - FAIL_HERE(); - case ';': - { - switch (LHSPROC[lhsIndex].value) - { - case FREQ: - if (this->freq != 0) { - FAIL_HERE(); - } - index = match_proc(FREQPROC, s, slen); - if (index >= 0) { - this->freq = (freq_t)FREQPROC[index].value; - } - break; - case UNTIL: - // XXX should check that this is a valid time - until.setTo(String16(s, slen)); - break; - case COUNT: - if (count != 0 - || NO_ERROR != parse_int(s, slen, - &count, INT_MIN, INT_MAX, true)) { - FAIL_HERE(); - } - break; - case INTERVAL: - if (interval != 0 - || NO_ERROR != parse_int(s, slen, - &interval, INT_MIN, INT_MAX, false)) { - FAIL_HERE(); - } - break; - case BYSECOND: - PARSE_INT_LIST_CHECKED(bysecond, 0, 59, true) - break; - case BYMINUTE: - PARSE_INT_LIST_CHECKED(byminute, 0, 59, true) - break; - case BYHOUR: - PARSE_INT_LIST_CHECKED(byhour, 0, 23, true) - break; - case BYDAY: - if (bydayCount != 0 || NO_ERROR != - parse_int_list(s, slen, &bydayCount, - &byday, -53, 53, false, - parse_byday)) { - FAIL_HERE(); - } - postprocess_byday(bydayCount, byday, &bydayNum); - break; - case BYMONTHDAY: - PARSE_INT_LIST_CHECKED(bymonthday, -31, 31, - false) - break; - case BYYEARDAY: - PARSE_INT_LIST_CHECKED(byyearday, -366, 366, - false) - break; - case BYWEEKNO: - PARSE_INT_LIST_CHECKED(byweekno, -53, 53, - false) - break; - case BYMONTH: - PARSE_INT_LIST_CHECKED(bymonth, 1, 12, false) - break; - case BYSETPOS: - PARSE_INT_LIST_CHECKED(bysetpos, - INT_MIN, INT_MAX, true) - break; - case WKST: - if (this->wkst != 0) { - FAIL_HERE(); - } - index = match_proc(WEEKDAYPROC, s, slen); - if (index >= 0) { - this->wkst = (int)WEEKDAYPROC[index].value; - } - break; - default: - FAIL_HERE(); - } - lhsIndex = NONE_LHS; - break; - } - } - - start = i+1; - } - } - } - - // enforce that there was a FREQ - if (freq == 0) { - FAIL_HERE(); - } - - // default wkst to MO if it wasn't specified - if (wkst == 0) { - wkst = MO; - } - - return NO_ERROR; -} - - -}; // namespace android - - diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index ffdfe66..c46d6f4 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -443,7 +443,8 @@ status_t InputPublisher::appendMotionSample( if (! mPinned || ! mMotionEventSampleDataTail) { LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current " - "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string()); + "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.", + mChannel->getName().string()); return INVALID_OPERATION; } diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 093189c..774e8c9 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -27,6 +27,7 @@ commonSources:= \ Debug.cpp \ FileMap.cpp \ Flattenable.cpp \ + LinearTransform.cpp \ ObbFile.cpp \ Pool.cpp \ PropertyMap.cpp \ diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp index f963058..8791263 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -285,7 +285,8 @@ BackupDataReader::ReadNextHeader(bool* done, int* type) break; } default: - LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type); + LOGD("Chunk header at %d has invalid type: 0x%08x", + (int)(m_pos - sizeof(m_header)), (int)m_header.type); m_status = EINVAL; } diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp new file mode 100644 index 0000000..d752415 --- /dev/null +++ b/libs/utils/LinearTransform.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2011 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 __STDC_LIMIT_MACROS + +#include <assert.h> +#include <stdint.h> + +#include <utils/LinearTransform.h> + +namespace android { + +template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; } + +// Static math methods involving linear transformations +static bool scale_u64_to_u64( + uint64_t val, + uint32_t N, + uint32_t D, + uint64_t* res, + bool round_up_not_down) { + uint64_t tmp1, tmp2; + uint32_t r; + + assert(res); + assert(D); + + // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit + // integer X. + // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit + // integer X. + // Let X[A, B] with A <= B denote bits A through B of the integer X. + // Let (A | B) denote the concatination of two 32 bit ints, A and B. + // IOW X = (A | B) => U32(X) == A && L32(X) == B + // + // compute M = val * N (a 96 bit int) + // --------------------------------- + // tmp2 = U32(val) * N (a 64 bit int) + // tmp1 = L32(val) * N (a 64 bit int) + // which means + // M = val * N = (tmp2 << 32) + tmp1 + tmp2 = (val >> 32) * N; + tmp1 = (val & UINT32_MAX) * N; + + // compute M[32, 95] + // tmp2 = tmp2 + U32(tmp1) + // = (U32(val) * N) + U32(L32(val) * N) + // = M[32, 95] + tmp2 += tmp1 >> 32; + + // if M[64, 95] >= D, then M/D has bits > 63 set and we have + // an overflow. + if ((tmp2 >> 32) >= D) { + *res = UINT64_MAX; + return false; + } + + // Divide. Going in we know + // tmp2 = M[32, 95] + // U32(tmp2) < D + r = tmp2 % D; + tmp2 /= D; + + // At this point + // tmp1 = L32(val) * N + // tmp2 = M[32, 95] / D + // = (M / D)[32, 95] + // r = M[32, 95] % D + // U32(tmp2) = 0 + // + // compute tmp1 = (r | M[0, 31]) + tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32); + + // Divide again. Keep the remainder around in order to round properly. + r = tmp1 % D; + tmp1 /= D; + + // At this point + // tmp2 = (M / D)[32, 95] + // tmp1 = (M / D)[ 0, 31] + // r = M % D + // U32(tmp1) = 0 + // U32(tmp2) = 0 + + // Pack the result and deal with the round-up case (As well as the + // remote possiblility over overflow in such a case). + *res = (tmp2 << 32) | tmp1; + if (r && round_up_not_down) { + ++(*res); + if (!(*res)) { + *res = UINT64_MAX; + return false; + } + } + + return true; +} + +static bool linear_transform_s64_to_s64( + int64_t val, + int64_t basis1, + int32_t N, + uint32_t D, + int64_t basis2, + int64_t* out) { + uint64_t scaled, res; + uint64_t abs_val; + bool is_neg; + + if (!out) + return false; + + // Compute abs(val - basis_64). Keep track of whether or not this delta + // will be negative after the scale opertaion. + if (val < basis1) { + is_neg = true; + abs_val = basis1 - val; + } else { + is_neg = false; + abs_val = val - basis1; + } + + if (N < 0) + is_neg = !is_neg; + + if (!scale_u64_to_u64(abs_val, + ABS(N), + D, + &scaled, + is_neg)) + return false; // overflow/undeflow + + // if scaled is >= 0x8000<etc>, then we are going to overflow or + // underflow unless ABS(basis2) is large enough to pull us back into the + // non-overflow/underflow region. + if (scaled & INT64_MIN) { + if (is_neg && (basis2 < 0)) + return false; // certain underflow + + if (!is_neg && (basis2 >= 0)) + return false; // certain overflow + + if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX)) + return false; // not enough + + // Looks like we are OK + *out = (is_neg ? (-scaled) : scaled) + basis2; + } else { + // Scaled fits within signed bounds, so we just need to check for + // over/underflow for two signed integers. Basically, if both scaled + // and basis2 have the same sign bit, and the result has a different + // sign bit, then we have under/overflow. An easy way to compute this + // is + // (scaled_signbit XNOR basis_signbit) && + // (scaled_signbit XOR res_signbit) + // == + // (scaled_signbit XOR basis_signbit XOR 1) && + // (scaled_signbit XOR res_signbit) + + if (is_neg) + scaled = -scaled; + res = scaled + basis2; + + if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN) + return false; + + *out = res; + } + + return true; +} + +bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const { + if (0 == a_to_b_denom) + return false; + + return linear_transform_s64_to_s64(a_in, + a_zero, + a_to_b_numer, + a_to_b_denom, + b_zero, + b_out); +} + +bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const { + if (0 == a_to_b_numer) + return false; + + return linear_transform_s64_to_s64(b_in, + b_zero, + a_to_b_denom, + a_to_b_numer, + a_zero, + a_out); +} + +template <class T> void LinearTransform::reduce(T* N, T* D) { + T a, b; + if (!N || !D || !(*D)) { + assert(false); + return; + } + + a = *N; + b = *D; + + if (a == 0) { + *D = 1; + return; + } + + // This implements Euclid's method to find GCD. + if (a < b) { + T tmp = a; + a = b; + b = tmp; + } + + while (1) { + // a is now the greater of the two. + const T remainder = a % b; + if (remainder == 0) { + *N /= b; + *D /= b; + return; + } + // by swapping remainder and b, we are guaranteeing that a is + // still the greater of the two upon entrance to the loop. + a = b; + b = remainder; + } +}; + +template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D); +template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D); + +void LinearTransform::reduce(int32_t* N, uint32_t* D) { + if (N && D && *D) { + if (*N < 0) { + *N = -(*N); + reduce(reinterpret_cast<uint32_t*>(N), D); + *N = -(*N); + } else { + reduce(reinterpret_cast<uint32_t*>(N), D); + } + } +} + +} // namespace android diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index 48ce5d1..50312e7 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -316,6 +316,10 @@ int androidSetThreadSchedulingGroup(pid_t tid, int grp) #if defined(HAVE_PTHREADS) pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); if (gDoSchedulingGroup) { + // set_sched_policy does not support tid == 0 + if (tid == 0) { + tid = androidGetTid(); + } if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ? SP_BACKGROUND : SP_FOREGROUND)) { return PERMISSION_DENIED; diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index a774841..33125c4 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -103,6 +103,11 @@ void DisplayHardware::init(uint32_t dpy) { mNativeWindow = new FramebufferNativeWindow(); framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); + if (!fbDev) { + LOGE("Display subsystem failed to initialize. check logs. exiting..."); + exit(0); + } + mDpiX = mNativeWindow->xdpi; mDpiY = mNativeWindow->ydpi; mRefreshRate = fbDev->fps; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2bab6a8..35e29a6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -101,9 +101,8 @@ Layer::~Layer() } void Layer::onFrameQueued() { - if (android_atomic_or(1, &mQueuedFrames) == 0) { - mFlinger->signalEvent(); - } + android_atomic_inc(&mQueuedFrames); + mFlinger->signalEvent(); } // called with SurfaceFlinger::mStateLock as soon as the layer is entered @@ -406,20 +405,18 @@ bool Layer::isCropped() const { void Layer::lockPageFlip(bool& recomputeVisibleRegions) { - if (android_atomic_and(0, &mQueuedFrames)) { + if (mQueuedFrames > 0) { + // signal another event if we have more frames pending + if (android_atomic_dec(&mQueuedFrames) > 1) { + mFlinger->signalEvent(); + } + if (mSurfaceTexture->updateTexImage() < NO_ERROR) { // something happened! recomputeVisibleRegions = true; return; } - // signal another event if we have more frames waiting - if (mSurfaceTexture->getQueuedCount()) { - if (android_atomic_or(1, &mQueuedFrames) == 0) { - mFlinger->signalEvent(); - } - } - mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); mSurfaceTexture->getTransformMatrix(mTextureMatrix); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 97edfee..cccab4a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -32,6 +32,7 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/MemoryHeapBase.h> +#include <binder/PermissionCache.h> #include <utils/String8.h> #include <utils/String16.h> @@ -67,17 +68,19 @@ namespace android { // --------------------------------------------------------------------------- +const String16 sHardwareTest("android.permission.HARDWARE_TEST"); +const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); +const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); +const String16 sDump("android.permission.DUMP"); + +// --------------------------------------------------------------------------- + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), mTransactionFlags(0), - mTransactionCount(0), mResizeTransationPending(false), mLayersRemoved(false), mBootTime(systemTime()), - mHardwareTest("android.permission.HARDWARE_TEST"), - mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), - mReadFramebuffer("android.permission.READ_FRAME_BUFFER"), - mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), mHwWorkListDirty(false), mDeferReleaseConsole(false), @@ -160,9 +163,34 @@ void SurfaceFlinger::bootFinished() const nsecs_t duration = now - mBootTime; LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mBootFinished = true; + + // wait patiently for the window manager death + const String16 name("window"); + sp<IBinder> window(defaultServiceManager()->getService(name)); + if (window != 0) { + window->linkToDeath(this); + } + + // stop boot animation property_set("ctl.stop", "bootanim"); } +void SurfaceFlinger::binderDied(const wp<IBinder>& who) +{ + // the window manager died on us. prepare its eulogy. + + // unfreeze the screen in case it was... frozen + mFreezeDisplayTime = 0; + mFreezeCount = 0; + mFreezeDisplay = false; + + // reset screen orientation + setOrientation(0, eOrientationDefault, 0); + + // restart the boot-animation + property_set("ctl.start", "bootanim"); +} + void SurfaceFlinger::onFirstRef() { run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY); @@ -381,13 +409,11 @@ bool SurfaceFlinger::threadLoop() handleConsoleEvents(); } - if (LIKELY(mTransactionCount == 0)) { - // if we're in a global transaction, don't do anything. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - uint32_t transactionFlags = peekTransactionFlags(mask); - if (LIKELY(transactionFlags)) { - handleTransaction(transactionFlags); - } + // if we're in a global transaction, don't do anything. + const uint32_t mask = eTransactionNeeded | eTraversalNeeded; + uint32_t transactionFlags = peekTransactionFlags(mask); + if (UNLIKELY(transactionFlags)) { + handleTransaction(transactionFlags); } // post surfaces (if needed) @@ -1172,28 +1198,33 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) return old; } -void SurfaceFlinger::openGlobalTransaction() -{ - android_atomic_inc(&mTransactionCount); -} -void SurfaceFlinger::closeGlobalTransaction() -{ - if (android_atomic_dec(&mTransactionCount) == 1) { - signalEvent(); +void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state) { + Mutex::Autolock _l(mStateLock); - // if there is a transaction with a resize, wait for it to - // take effect before returning. - Mutex::Autolock _l(mStateLock); - while (mResizeTransationPending) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - // just in case something goes wrong in SF, return to the - // called after a few seconds. - LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!"); - mResizeTransationPending = false; - break; - } + uint32_t flags = 0; + const size_t count = state.size(); + for (size_t i=0 ; i<count ; i++) { + const ComposerState& s(state[i]); + sp<Client> client( static_cast<Client *>(s.client.get()) ); + flags |= setClientStateLocked(client, s.state); + } + if (flags) { + setTransactionFlags(flags); + } + + signalEvent(); + + // if there is a transaction with a resize, wait for it to + // take effect before returning. + while (mResizeTransationPending) { + status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); + if (CC_UNLIKELY(err != NO_ERROR)) { + // just in case something goes wrong in SF, return to the + // called after a few seconds. + LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!"); + mResizeTransationPending = false; + break; } } } @@ -1389,60 +1420,52 @@ status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer) return err; } -status_t SurfaceFlinger::setClientState( +uint32_t SurfaceFlinger::setClientStateLocked( const sp<Client>& client, - int32_t count, - const layer_state_t* states) + const layer_state_t& s) { - Mutex::Autolock _l(mStateLock); uint32_t flags = 0; - for (int i=0 ; i<count ; i++) { - const layer_state_t& s(states[i]); - sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); - if (layer != 0) { - const uint32_t what = s.what; - if (what & ePositionChanged) { - if (layer->setPosition(s.x, s.y)) - flags |= eTraversalNeeded; - } - if (what & eLayerChanged) { - ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setLayer(s.z)) { - mCurrentState.layersSortedByZ.removeAt(idx); - mCurrentState.layersSortedByZ.add(layer); - // we need traversal (state changed) - // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - mResizeTransationPending = true; - } - } - if (what & eAlphaChanged) { - if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) - flags |= eTraversalNeeded; - } - if (what & eMatrixChanged) { - if (layer->setMatrix(s.matrix)) - flags |= eTraversalNeeded; - } - if (what & eTransparentRegionChanged) { - if (layer->setTransparentRegionHint(s.transparentRegion)) - flags |= eTraversalNeeded; + sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); + if (layer != 0) { + const uint32_t what = s.what; + if (what & ePositionChanged) { + if (layer->setPosition(s.x, s.y)) + flags |= eTraversalNeeded; + } + if (what & eLayerChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayer(s.z)) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; } - if (what & eVisibilityChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; + } + if (what & eSizeChanged) { + if (layer->setSize(s.w, s.h)) { + flags |= eTraversalNeeded; + mResizeTransationPending = true; } } + if (what & eAlphaChanged) { + if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) + flags |= eTraversalNeeded; + } + if (what & eMatrixChanged) { + if (layer->setMatrix(s.matrix)) + flags |= eTraversalNeeded; + } + if (what & eTransparentRegionChanged) { + if (layer->setTransparentRegionHint(s.transparentRegion)) + flags |= eTraversalNeeded; + } + if (what & eVisibilityChanged) { + if (layer->setFlags(s.flags, s.mask)) + flags |= eTraversalNeeded; + } } - if (flags) { - setTransactionFlags(flags); - } - return NO_ERROR; + return flags; } void SurfaceFlinger::screenReleased(int dpy) @@ -1464,7 +1487,8 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) const size_t SIZE = 4096; char buffer[SIZE]; String8 result; - if (!mDump.checkCalling()) { + + if (!PermissionCache::checkCallingPermission(sDump)) { snprintf(buffer, SIZE, "Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", IPCThreadState::self()->getCallingPid(), @@ -1583,8 +1607,7 @@ status_t SurfaceFlinger::onTransact( { switch (code) { case CREATE_CONNECTION: - case OPEN_GLOBAL_TRANSACTION: - case CLOSE_GLOBAL_TRANSACTION: + case SET_TRANSACTION_STATE: case SET_ORIENTATION: case FREEZE_DISPLAY: case UNFREEZE_DISPLAY: @@ -1596,7 +1619,8 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) { + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { LOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; @@ -1609,7 +1633,8 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) { + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { LOGE("Permission Denial: " "can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; @@ -1621,7 +1646,7 @@ status_t SurfaceFlinger::onTransact( status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); - if (UNLIKELY(!mHardwareTest.checkCalling())) { + if (UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -1799,10 +1824,10 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() const GLfloat h = hw_h - (hw_h * v); const GLfloat x = (hw_w - w) * 0.5f; const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; + vtx[0] = x; vtx[1] = y + h; + vtx[2] = x; vtx[3] = y; + vtx[4] = x + w; vtx[5] = y; + vtx[6] = x + w; vtx[7] = y + h; } }; @@ -1817,10 +1842,10 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() const GLfloat h = 1.0f; const GLfloat x = (hw_w - w) * 0.5f; const GLfloat y = (hw_h - h) * 0.5f; - vtx[0] = x; vtx[1] = y; - vtx[2] = x; vtx[3] = y + h; - vtx[4] = x + w; vtx[5] = y + h; - vtx[6] = x + w; vtx[7] = y; + vtx[0] = x; vtx[1] = y + h; + vtx[2] = x; vtx[3] = y; + vtx[4] = x + w; vtx[5] = y; + vtx[6] = x + w; vtx[7] = y + h; } }; @@ -2404,8 +2429,7 @@ status_t Client::onTransact( const int self_pid = getpid(); if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { // we're called from a different process, do the real check - if (!checkCallingPermission( - String16("android.permission.ACCESS_SURFACE_FLINGER"))) + if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { LOGE("Permission Denial: " "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); @@ -2463,9 +2487,6 @@ sp<ISurface> Client::createSurface( status_t Client::destroySurface(SurfaceID sid) { return mFlinger->removeSurface(this, sid); } -status_t Client::setState(int32_t count, const layer_state_t* states) { - return mFlinger->setClientState(this, count, states); -} // --------------------------------------------------------------------------- @@ -2474,11 +2495,14 @@ GraphicBufferAlloc::GraphicBufferAlloc() {} GraphicBufferAlloc::~GraphicBufferAlloc() {} sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage) { + PixelFormat format, uint32_t usage, status_t* error) { sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); status_t err = graphicBuffer->initCheck(); + *error = err; if (err != 0 || graphicBuffer->handle == 0) { - GraphicBuffer::dumpAllocationsToSystemLog(); + if (err == NO_MEMORY) { + GraphicBuffer::dumpAllocationsToSystemLog(); + } LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " "failed (%s), handle=%p", w, h, strerror(-err), graphicBuffer->handle); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index af1ef04..15661f0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -20,21 +20,20 @@ #include <stdint.h> #include <sys/types.h> -#include <utils/SortedVector.h> -#include <utils/KeyedVector.h> -#include <utils/threads.h> #include <utils/Atomic.h> #include <utils/Errors.h> +#include <utils/KeyedVector.h> #include <utils/RefBase.h> +#include <utils/SortedVector.h> +#include <utils/threads.h> -#include <binder/IMemory.h> -#include <binder/Permission.h> #include <binder/BinderService.h> +#include <binder/IMemory.h> #include <ui/PixelFormat.h> +#include <surfaceflinger/IGraphicBufferAlloc.h> #include <surfaceflinger/ISurfaceComposer.h> #include <surfaceflinger/ISurfaceComposerClient.h> -#include <surfaceflinger/IGraphicBufferAlloc.h> #include "Barrier.h" #include "Layer.h" @@ -71,14 +70,12 @@ public: sp<LayerBaseClient> getLayerUser(int32_t i) const; private: - // ISurfaceComposerClient interface virtual sp<ISurface> createSurface( surface_data_t* params, const String8& name, DisplayID display, uint32_t w, uint32_t h,PixelFormat format, uint32_t flags); virtual status_t destroySurface(SurfaceID surfaceId); - virtual status_t setState(int32_t count, const layer_state_t* states); virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); @@ -99,7 +96,7 @@ public: GraphicBufferAlloc(); virtual ~GraphicBufferAlloc(); virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage); + PixelFormat format, uint32_t usage, status_t* error); }; // --------------------------------------------------------------------------- @@ -150,6 +147,7 @@ enum { class SurfaceFlinger : public BinderService<SurfaceFlinger>, public BnSurfaceComposer, + public IBinder::DeathRecipient, protected Thread { public: @@ -169,8 +167,7 @@ public: virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc(); virtual sp<IMemoryHeap> getCblk() const; virtual void bootFinished(); - virtual void openGlobalTransaction(); - virtual void closeGlobalTransaction(); + virtual void setTransactionState(const Vector<ComposerState>& state); virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags); virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags); virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags); @@ -197,6 +194,10 @@ public: sp<Layer> getLayer(const sp<ISurface>& sur) const; private: + // DeathRecipient interface + virtual void binderDied(const wp<IBinder>& who); + +private: friend class Client; friend class LayerBase; friend class LayerBaseClient; @@ -221,8 +222,7 @@ private: status_t removeSurface(const sp<Client>& client, SurfaceID sid); status_t destroySurface(const wp<LayerBaseClient>& layer); - status_t setClientState(const sp<Client>& client, - int32_t count, const layer_state_t* states); + uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s); class LayerVector : public SortedVector< sp<LayerBase> > { public: @@ -338,7 +338,6 @@ private: mutable Mutex mStateLock; State mCurrentState; volatile int32_t mTransactionFlags; - volatile int32_t mTransactionCount; Condition mTransactionCV; SortedVector< sp<LayerBase> > mLayerPurgatory; bool mResizeTransationPending; @@ -353,11 +352,7 @@ private: surface_flinger_cblk_t* mServerCblk; GLuint mWormholeTexName; nsecs_t mBootTime; - Permission mHardwareTest; - Permission mAccessSurfaceFlinger; - Permission mReadFramebuffer; - Permission mDump; - + // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState; diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp index 18c54b3..56b2a8f 100644 --- a/services/surfaceflinger/tests/resize/resize.cpp +++ b/services/surfaceflinger/tests/resize/resize.cpp @@ -43,9 +43,9 @@ int main(int argc, char** argv) PIXEL_FORMAT_RGB_565); - client->openTransaction(); + SurfaceComposerClient::openGlobalTransaction(); surface->setLayer(100000); - client->closeTransaction(); + SurfaceComposerClient::closeGlobalTransaction(); Surface::SurfaceInfo info; surface->lock(&info); @@ -57,9 +57,9 @@ int main(int argc, char** argv) android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h); surface->unlockAndPost(); - client->openTransaction(); + SurfaceComposerClient::openGlobalTransaction(); surface->setSize(320, 240); - client->closeTransaction(); + SurfaceComposerClient::closeGlobalTransaction(); IPCThreadState::self()->joinThreadPool(); diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp index 5265f91..8e1c3fe 100644 --- a/services/surfaceflinger/tests/surface/surface.cpp +++ b/services/surfaceflinger/tests/surface/surface.cpp @@ -39,9 +39,9 @@ int main(int argc, char** argv) sp<SurfaceControl> surfaceControl = client->createSurface( getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565); - client->openTransaction(); + SurfaceComposerClient::openGlobalTransaction(); surfaceControl->setLayer(100000); - client->closeTransaction(); + SurfaceComposerClient::closeGlobalTransaction(); // pretend it went cross-process Parcel parcel; diff --git a/vpn/java/android/net/vpn/IVpnService.aidl b/vpn/java/android/net/vpn/IVpnService.aidl deleted file mode 100644 index 6bf3edd..0000000 --- a/vpn/java/android/net/vpn/IVpnService.aidl +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.net.vpn.VpnProfile; - -/** - * Interface to access a VPN service. - * {@hide} - */ -interface IVpnService { - /** - * Sets up a VPN connection. - * @param profile the profile object - * @param username the username for authentication - * @param password the corresponding password for authentication - * @return true if VPN is successfully connected - */ - boolean connect(in VpnProfile profile, String username, String password); - - /** - * Tears down the VPN connection. - */ - void disconnect(); - - /** - * Gets the the current connection state. - */ - String getState(in VpnProfile profile); - - /** - * Returns the idle state. - * @return true if the system is not connecting/connected to a VPN - */ - boolean isIdle(); -} diff --git a/vpn/java/android/net/vpn/L2tpIpsecProfile.java b/vpn/java/android/net/vpn/L2tpIpsecProfile.java deleted file mode 100644 index 4ae2dec..0000000 --- a/vpn/java/android/net/vpn/L2tpIpsecProfile.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.os.Parcel; - -/** - * The profile for certificate-based L2TP-over-IPSec type of VPN. - * {@hide} - */ -public class L2tpIpsecProfile extends L2tpProfile { - private static final long serialVersionUID = 1L; - - private String mUserCertificate; - private String mCaCertificate; - - @Override - public VpnType getType() { - return VpnType.L2TP_IPSEC; - } - - public void setCaCertificate(String name) { - mCaCertificate = name; - } - - public String getCaCertificate() { - return mCaCertificate; - } - - public void setUserCertificate(String name) { - mUserCertificate = name; - } - - public String getUserCertificate() { - return mUserCertificate; - } - - @Override - protected void readFromParcel(Parcel in) { - super.readFromParcel(in); - mCaCertificate = in.readString(); - mUserCertificate = in.readString(); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - super.writeToParcel(parcel, flags); - parcel.writeString(mCaCertificate); - parcel.writeString(mUserCertificate); - } -} diff --git a/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java b/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java deleted file mode 100644 index 7a03018..0000000 --- a/vpn/java/android/net/vpn/L2tpIpsecPskProfile.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.os.Parcel; - -/** - * The profile for pre-shared-key-based L2TP-over-IPSec type of VPN. - * {@hide} - */ -public class L2tpIpsecPskProfile extends L2tpProfile { - private static final long serialVersionUID = 1L; - - private String mPresharedKey; - - @Override - public VpnType getType() { - return VpnType.L2TP_IPSEC_PSK; - } - - public void setPresharedKey(String key) { - mPresharedKey = key; - } - - public String getPresharedKey() { - return mPresharedKey; - } - - @Override - protected void readFromParcel(Parcel in) { - super.readFromParcel(in); - mPresharedKey = in.readString(); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - super.writeToParcel(parcel, flags); - parcel.writeString(mPresharedKey); - } -} diff --git a/vpn/java/android/net/vpn/L2tpProfile.java b/vpn/java/android/net/vpn/L2tpProfile.java deleted file mode 100644 index dbba0c5..0000000 --- a/vpn/java/android/net/vpn/L2tpProfile.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.os.Parcel; - -/** - * The profile for L2TP type of VPN. - * {@hide} - */ -public class L2tpProfile extends VpnProfile { - private static final long serialVersionUID = 1L; - - private boolean mSecret; - private String mSecretString; - - @Override - public VpnType getType() { - return VpnType.L2TP; - } - - /** - * Enables/disables the secret for authenticating tunnel connection. - */ - public void setSecretEnabled(boolean enabled) { - mSecret = enabled; - } - - public boolean isSecretEnabled() { - return mSecret; - } - - public void setSecretString(String secret) { - mSecretString = secret; - } - - public String getSecretString() { - return mSecretString; - } - - @Override - protected void readFromParcel(Parcel in) { - super.readFromParcel(in); - mSecret = in.readInt() > 0; - mSecretString = in.readString(); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - super.writeToParcel(parcel, flags); - parcel.writeInt(mSecret ? 1 : 0); - parcel.writeString(mSecretString); - } -} diff --git a/vpn/java/android/net/vpn/PptpProfile.java b/vpn/java/android/net/vpn/PptpProfile.java deleted file mode 100644 index b4b7be5..0000000 --- a/vpn/java/android/net/vpn/PptpProfile.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.os.Parcel; - -/** - * The profile for PPTP type of VPN. - * {@hide} - */ -public class PptpProfile extends VpnProfile { - private static final long serialVersionUID = 1L; - private boolean mEncryption = true; - - @Override - public VpnType getType() { - return VpnType.PPTP; - } - - /** - * Enables/disables the encryption for PPTP tunnel. - */ - public void setEncryptionEnabled(boolean enabled) { - mEncryption = enabled; - } - - public boolean isEncryptionEnabled() { - return mEncryption; - } - - @Override - protected void readFromParcel(Parcel in) { - super.readFromParcel(in); - mEncryption = in.readInt() > 0; - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - super.writeToParcel(parcel, flags); - parcel.writeInt(mEncryption ? 1 : 0); - } -} diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java deleted file mode 100644 index 02486bb..0000000 --- a/vpn/java/android/net/vpn/VpnManager.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Environment; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemProperties; -import android.util.Log; - -import com.android.server.vpn.VpnServiceBinder; - -/** - * The class provides interface to manage all VPN-related tasks, including: - * <ul> - * <li>The list of supported VPN types. - * <li>API's to start/stop the service of a particular type. - * <li>API's to start the settings activity. - * <li>API's to create a profile. - * <li>API's to register/unregister a connectivity receiver and the keys to - * access the fields in a connectivity broadcast event. - * </ul> - * {@hide} - */ -public class VpnManager { - /** Key to the profile name of a connectivity broadcast event. */ - public static final String BROADCAST_PROFILE_NAME = "profile_name"; - /** Key to the connectivity state of a connectivity broadcast event. */ - public static final String BROADCAST_CONNECTION_STATE = "connection_state"; - /** Key to the error code of a connectivity broadcast event. */ - public static final String BROADCAST_ERROR_CODE = "err"; - /** Error code to indicate an error from authentication. */ - public static final int VPN_ERROR_AUTH = 51; - /** Error code to indicate the connection attempt failed. */ - public static final int VPN_ERROR_CONNECTION_FAILED = 101; - /** Error code to indicate the server is not known. */ - public static final int VPN_ERROR_UNKNOWN_SERVER = 102; - /** Error code to indicate an error from challenge response. */ - public static final int VPN_ERROR_CHALLENGE = 5; - /** Error code to indicate an error of remote server hanging up. */ - public static final int VPN_ERROR_REMOTE_HUNG_UP = 7; - /** Error code to indicate an error of remote PPP server hanging up. */ - public static final int VPN_ERROR_REMOTE_PPP_HUNG_UP = 48; - /** Error code to indicate a PPP negotiation error. */ - public static final int VPN_ERROR_PPP_NEGOTIATION_FAILED = 42; - /** Error code to indicate an error of losing connectivity. */ - public static final int VPN_ERROR_CONNECTION_LOST = 103; - /** Largest error code used by VPN. */ - public static final int VPN_ERROR_LARGEST = 200; - /** Error code to indicate a successful connection. */ - public static final int VPN_ERROR_NO_ERROR = 0; - - public static final String PROFILES_PATH = "/misc/vpn/profiles"; - - private static final String PACKAGE_PREFIX = - VpnManager.class.getPackage().getName() + "."; - - // Action for broadcasting a connectivity state. - private static final String ACTION_VPN_CONNECTIVITY = "vpn.connectivity"; - - private static final String VPN_SERVICE_NAME = "vpn"; - - // Action to start VPN settings - private static final String ACTION_VPN_SETTINGS = - PACKAGE_PREFIX + "SETTINGS"; - - public static final String TAG = VpnManager.class.getSimpleName(); - - // TODO(oam): Test VPN when EFS is enabled (will do later)... - public static String getProfilePath() { - // This call will return the correct path if Encrypted FS is enabled or not. - return Environment.getSecureDataDirectory().getPath() + PROFILES_PATH; - } - - /** - * Returns all supported VPN types. - */ - public static VpnType[] getSupportedVpnTypes() { - return VpnType.values(); - } - - public static void startVpnService(Context c) { - ServiceManager.addService(VPN_SERVICE_NAME, new VpnServiceBinder(c)); - } - - private Context mContext; - private IVpnService mVpnService; - - /** - * Creates a manager object with the specified context. - */ - public VpnManager(Context c) { - mContext = c; - createVpnServiceClient(); - } - - private void createVpnServiceClient() { - IBinder b = ServiceManager.getService(VPN_SERVICE_NAME); - mVpnService = IVpnService.Stub.asInterface(b); - } - - /** - * Sets up a VPN connection. - * @param profile the profile object - * @param username the username for authentication - * @param password the corresponding password for authentication - * @return true if VPN is successfully connected - */ - public boolean connect(VpnProfile p, String username, String password) { - try { - return mVpnService.connect(p, username, password); - } catch (RemoteException e) { - Log.e(TAG, "connect()", e); - return false; - } - } - - /** - * Tears down the VPN connection. - */ - public void disconnect() { - try { - mVpnService.disconnect(); - } catch (RemoteException e) { - Log.e(TAG, "disconnect()", e); - } - } - - /** - * Gets the the current connection state. - */ - public VpnState getState(VpnProfile p) { - try { - return Enum.valueOf(VpnState.class, mVpnService.getState(p)); - } catch (RemoteException e) { - Log.e(TAG, "getState()", e); - return VpnState.IDLE; - } - } - - /** - * Returns the idle state. - * @return true if the system is not connecting/connected to a VPN - */ - public boolean isIdle() { - try { - return mVpnService.isIdle(); - } catch (RemoteException e) { - Log.e(TAG, "isIdle()", e); - return true; - } - } - - /** - * Creates a VPN profile of the specified type. - * - * @param type the VPN type - * @return the profile object - */ - public VpnProfile createVpnProfile(VpnType type) { - return createVpnProfile(type, false); - } - - /** - * Creates a VPN profile of the specified type. - * - * @param type the VPN type - * @param customized true if the profile is custom made - * @return the profile object - */ - public VpnProfile createVpnProfile(VpnType type, boolean customized) { - try { - VpnProfile p = (VpnProfile) type.getProfileClass().newInstance(); - p.setCustomized(customized); - return p; - } catch (InstantiationException e) { - return null; - } catch (IllegalAccessException e) { - return null; - } - } - - /** Broadcasts the connectivity state of the specified profile. */ - public void broadcastConnectivity(String profileName, VpnState s) { - broadcastConnectivity(profileName, s, VPN_ERROR_NO_ERROR); - } - - /** Broadcasts the connectivity state with an error code. */ - public void broadcastConnectivity(String profileName, VpnState s, - int error) { - Intent intent = new Intent(ACTION_VPN_CONNECTIVITY); - intent.putExtra(BROADCAST_PROFILE_NAME, profileName); - intent.putExtra(BROADCAST_CONNECTION_STATE, s); - if (error != VPN_ERROR_NO_ERROR) { - intent.putExtra(BROADCAST_ERROR_CODE, error); - } - mContext.sendBroadcast(intent); - } - - public void registerConnectivityReceiver(BroadcastReceiver r) { - IntentFilter filter = new IntentFilter(); - filter.addAction(VpnManager.ACTION_VPN_CONNECTIVITY); - mContext.registerReceiver(r, filter); - } - - public void unregisterConnectivityReceiver(BroadcastReceiver r) { - mContext.unregisterReceiver(r); - } - - /** Starts the VPN settings activity. */ - public void startSettingsActivity() { - Intent intent = new Intent(ACTION_VPN_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - } - - /** Creates an intent to start the VPN settings activity. */ - public Intent createSettingsActivityIntent() { - Intent intent = new Intent(ACTION_VPN_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - return intent; - } -} diff --git a/vpn/java/android/net/vpn/VpnProfile.aidl b/vpn/java/android/net/vpn/VpnProfile.aidl deleted file mode 100644 index edeaef0..0000000 --- a/vpn/java/android/net/vpn/VpnProfile.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -parcelable VpnProfile; diff --git a/vpn/java/android/net/vpn/VpnProfile.java b/vpn/java/android/net/vpn/VpnProfile.java deleted file mode 100644 index bd6c809..0000000 --- a/vpn/java/android/net/vpn/VpnProfile.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.content.Context; -import android.os.Parcel; -import android.os.Parcelable; - -import java.io.IOException; -import java.io.Serializable; - -/** - * A VPN profile. - * {@hide} - */ -public abstract class VpnProfile implements Parcelable, Serializable { - private static final long serialVersionUID = 1L; - private String mName; // unique display name - private String mId; // unique identifier - private String mServerName; // VPN server name - private String mDomainSuffices; // space separated list - private String mRouteList; // space separated list - private String mSavedUsername; - private boolean mIsCustomized; - private transient VpnState mState = VpnState.IDLE; - - /** Sets a user-friendly name for this profile. */ - public void setName(String name) { - mName = name; - } - - public String getName() { - return mName; - } - - /** - * Sets an ID for this profile. The caller should make sure the - * uniqueness of the ID. - */ - public void setId(String id) { - mId = id; - } - - public String getId() { - return mId; - } - - /** - * Sets the name of the VPN server. Used for DNS lookup. - */ - public void setServerName(String name) { - mServerName = name; - } - - public String getServerName() { - return mServerName; - } - - /** - * Sets the domain suffices for DNS resolution. - * - * @param entries a comma-separated list of domain suffices - */ - public void setDomainSuffices(String entries) { - mDomainSuffices = entries; - } - - public String getDomainSuffices() { - return mDomainSuffices; - } - - /** - * Sets the routing info for this VPN connection. - * - * @param entries a comma-separated list of routes; each entry is in the - * format of "(network address)/(network mask)" - */ - public void setRouteList(String entries) { - mRouteList = entries; - } - - public String getRouteList() { - return mRouteList; - } - - public void setSavedUsername(String name) { - mSavedUsername = name; - } - - public String getSavedUsername() { - return mSavedUsername; - } - - public void setState(VpnState state) { - mState = state; - } - - public VpnState getState() { - return ((mState == null) ? VpnState.IDLE : mState); - } - - public boolean isIdle() { - return (mState == VpnState.IDLE); - } - - /** - * Returns whether this profile is custom made (as opposed to being - * created by provided user interface). - */ - public boolean isCustomized() { - return mIsCustomized; - } - - /** - * Returns the VPN type of the profile. - */ - public abstract VpnType getType(); - - void setCustomized(boolean customized) { - mIsCustomized = customized; - } - - protected void readFromParcel(Parcel in) { - mName = in.readString(); - mId = in.readString(); - mServerName = in.readString(); - mDomainSuffices = in.readString(); - mRouteList = in.readString(); - mSavedUsername = in.readString(); - } - - public static final Parcelable.Creator<VpnProfile> CREATOR = - new Parcelable.Creator<VpnProfile>() { - public VpnProfile createFromParcel(Parcel in) { - VpnType type = Enum.valueOf(VpnType.class, in.readString()); - boolean customized = in.readInt() > 0; - VpnProfile p = new VpnManager(null).createVpnProfile(type, - customized); - if (p == null) return null; - p.readFromParcel(in); - return p; - } - - public VpnProfile[] newArray(int size) { - return new VpnProfile[size]; - } - }; - - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeString(getType().toString()); - parcel.writeInt(mIsCustomized ? 1 : 0); - parcel.writeString(mName); - parcel.writeString(mId); - parcel.writeString(mServerName); - parcel.writeString(mDomainSuffices); - parcel.writeString(mRouteList); - parcel.writeString(mSavedUsername); - } - - public int describeContents() { - return 0; - } -} diff --git a/vpn/java/android/net/vpn/VpnState.java b/vpn/java/android/net/vpn/VpnState.java deleted file mode 100644 index 6e61f9c..0000000 --- a/vpn/java/android/net/vpn/VpnState.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -/** - * Enumeration of all VPN states. - * - * A normal VPN connection lifetime starts in {@link IDLE}. When a new - * connection is about to be set up, it goes to {@link CONNECTING} and then - * {@link CONNECTED} if successful; back to {@link IDLE} if failed. - * When the connection is about to be torn down, it goes to - * {@link DISCONNECTING} and then {@link IDLE}. - * {@link CANCELLED} is a state when a VPN connection attempt is aborted, and - * is in transition to {@link IDLE}. - * The {@link UNUSABLE} state indicates that the profile is not in a state for - * connecting due to possibly the integrity of the fields or another profile is - * connecting etc. - * The {@link UNKNOWN} state indicates that the profile state is to be - * determined. - * {@hide} - */ -public enum VpnState { - CONNECTING, DISCONNECTING, CANCELLED, CONNECTED, IDLE, UNUSABLE, UNKNOWN -} diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java deleted file mode 100644 index 356f8b1..0000000 --- a/vpn/java/android/net/vpn/VpnType.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import com.android.internal.R; - -/** - * Enumeration of all supported VPN types. - * {@hide} - */ -public enum VpnType { - PPTP("PPTP", R.string.pptp_vpn_description, PptpProfile.class), - L2TP("L2TP", R.string.l2tp_vpn_description, L2tpProfile.class), - L2TP_IPSEC_PSK("L2TP/IPSec PSK", R.string.l2tp_ipsec_psk_vpn_description, - L2tpIpsecPskProfile.class), - L2TP_IPSEC("L2TP/IPSec CRT", R.string.l2tp_ipsec_crt_vpn_description, - L2tpIpsecProfile.class); - - private String mDisplayName; - private int mDescriptionId; - private Class<? extends VpnProfile> mClass; - - VpnType(String displayName, int descriptionId, - Class<? extends VpnProfile> klass) { - mDisplayName = displayName; - mDescriptionId = descriptionId; - mClass = klass; - } - - public String getDisplayName() { - return mDisplayName; - } - - public int getDescriptionId() { - return mDescriptionId; - } - - public Class<? extends VpnProfile> getProfileClass() { - return mClass; - } -} diff --git a/vpn/java/com/android/server/vpn/DaemonProxy.java b/vpn/java/com/android/server/vpn/DaemonProxy.java deleted file mode 100644 index 289ee45..0000000 --- a/vpn/java/com/android/server/vpn/DaemonProxy.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.net.vpn.VpnManager; -import android.os.SystemProperties; -import android.util.Log; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Serializable; - -/** - * Proxy to start, stop and interact with a VPN daemon. - * The daemon is expected to accept connection through Unix domain socket. - * When the proxy successfully starts the daemon, it will establish a socket - * connection with the daemon, to both send commands to the daemon and receive - * response and connecting error code from the daemon. - */ -class DaemonProxy implements Serializable { - private static final long serialVersionUID = 1L; - private static final boolean DBG = true; - - private static final int WAITING_TIME = 15; // sec - - private static final String SVC_STATE_CMD_PREFIX = "init.svc."; - private static final String SVC_START_CMD = "ctl.start"; - private static final String SVC_STOP_CMD = "ctl.stop"; - private static final String SVC_STATE_RUNNING = "running"; - private static final String SVC_STATE_STOPPED = "stopped"; - - private static final int END_OF_ARGUMENTS = 255; - - private String mName; - private String mTag; - private transient LocalSocket mControlSocket; - - /** - * Creates a proxy of the specified daemon. - * @param daemonName name of the daemon - */ - DaemonProxy(String daemonName) { - mName = daemonName; - mTag = "SProxy_" + daemonName; - } - - String getName() { - return mName; - } - - void start() throws IOException { - String svc = mName; - - Log.i(mTag, "Start VPN daemon: " + svc); - SystemProperties.set(SVC_START_CMD, svc); - - if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) { - throw new IOException("cannot start service: " + svc); - } else { - mControlSocket = createServiceSocket(); - } - } - - void sendCommand(String ...args) throws IOException { - OutputStream out = getControlSocketOutput(); - for (String arg : args) outputString(out, arg); - out.write(END_OF_ARGUMENTS); - out.flush(); - - int result = getResultFromSocket(true); - if (result != args.length) { - throw new IOException("socket error, result from service: " - + result); - } - } - - // returns 0 if nothing is in the receive buffer - int getResultFromSocket() throws IOException { - return getResultFromSocket(false); - } - - void closeControlSocket() { - if (mControlSocket == null) return; - try { - mControlSocket.close(); - } catch (IOException e) { - Log.w(mTag, "close control socket", e); - } finally { - mControlSocket = null; - } - } - - void stop() { - String svc = mName; - Log.i(mTag, "Stop VPN daemon: " + svc); - SystemProperties.set(SVC_STOP_CMD, svc); - boolean success = blockUntil(SVC_STATE_STOPPED, 5); - if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success); - } - - boolean isStopped() { - String cmd = SVC_STATE_CMD_PREFIX + mName; - return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd)); - } - - private int getResultFromSocket(boolean blocking) throws IOException { - LocalSocket s = mControlSocket; - if (s == null) return 0; - InputStream in = s.getInputStream(); - if (!blocking && in.available() == 0) return 0; - - int data = in.read(); - Log.i(mTag, "got data from control socket: " + data); - - return data; - } - - private LocalSocket createServiceSocket() throws IOException { - LocalSocket s = new LocalSocket(); - LocalSocketAddress a = new LocalSocketAddress(mName, - LocalSocketAddress.Namespace.RESERVED); - - // try a few times in case the service has not listen()ed - IOException excp = null; - for (int i = 0; i < 10; i++) { - try { - s.connect(a); - return s; - } catch (IOException e) { - if (DBG) Log.d(mTag, "service not yet listen()ing; try again"); - excp = e; - sleep(500); - } - } - throw excp; - } - - private OutputStream getControlSocketOutput() throws IOException { - if (mControlSocket != null) { - return mControlSocket.getOutputStream(); - } else { - throw new IOException("no control socket available"); - } - } - - /** - * Waits for the process to be in the expected state. The method returns - * false if after the specified duration (in seconds), the process is still - * not in the expected state. - */ - private boolean blockUntil(String expectedState, int waitTime) { - String cmd = SVC_STATE_CMD_PREFIX + mName; - int sleepTime = 200; // ms - int n = waitTime * 1000 / sleepTime; - for (int i = 0; i < n; i++) { - if (expectedState.equals(SystemProperties.get(cmd))) { - if (DBG) { - Log.d(mTag, mName + " is " + expectedState + " after " - + (i * sleepTime) + " msec"); - } - break; - } - sleep(sleepTime); - } - return expectedState.equals(SystemProperties.get(cmd)); - } - - private void outputString(OutputStream out, String s) throws IOException { - byte[] bytes = s.getBytes(); - out.write(bytes.length); - out.write(bytes); - out.flush(); - } - - private void sleep(int msec) { - try { - Thread.currentThread().sleep(msec); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/vpn/java/com/android/server/vpn/L2tpIpsecPskService.java b/vpn/java/com/android/server/vpn/L2tpIpsecPskService.java deleted file mode 100644 index 50e0de1..0000000 --- a/vpn/java/com/android/server/vpn/L2tpIpsecPskService.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.net.vpn.L2tpIpsecPskProfile; - -import java.io.IOException; - -/** - * The service that manages the preshared key based L2TP-over-IPSec VPN - * connection. - */ -class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> { - private static final String IPSEC = "racoon"; - - @Override - protected void connect(String serverIp, String username, String password) - throws IOException { - L2tpIpsecPskProfile p = getProfile(); - VpnDaemons daemons = getDaemons(); - - // IPSEC - daemons.startIpsecForL2tp(serverIp, p.getPresharedKey()) - .closeControlSocket(); - - sleep(2000); // 2 seconds - - // L2TP - daemons.startL2tp(serverIp, - (p.isSecretEnabled() ? p.getSecretString() : null), - username, password); - } -} diff --git a/vpn/java/com/android/server/vpn/L2tpIpsecService.java b/vpn/java/com/android/server/vpn/L2tpIpsecService.java deleted file mode 100644 index 663b0e8..0000000 --- a/vpn/java/com/android/server/vpn/L2tpIpsecService.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.net.vpn.L2tpIpsecProfile; -import android.security.Credentials; - -import java.io.IOException; - -/** - * The service that manages the certificate based L2TP-over-IPSec VPN connection. - */ -class L2tpIpsecService extends VpnService<L2tpIpsecProfile> { - private static final String IPSEC = "racoon"; - - @Override - protected void connect(String serverIp, String username, String password) - throws IOException { - L2tpIpsecProfile p = getProfile(); - VpnDaemons daemons = getDaemons(); - - // IPSEC - DaemonProxy ipsec = daemons.startIpsecForL2tp(serverIp, - Credentials.USER_PRIVATE_KEY + p.getUserCertificate(), - Credentials.USER_CERTIFICATE + p.getUserCertificate(), - Credentials.CA_CERTIFICATE + p.getCaCertificate()); - ipsec.closeControlSocket(); - - sleep(2000); // 2 seconds - - // L2TP - daemons.startL2tp(serverIp, - (p.isSecretEnabled() ? p.getSecretString() : null), - username, password); - } -} diff --git a/vpn/java/com/android/server/vpn/L2tpService.java b/vpn/java/com/android/server/vpn/L2tpService.java deleted file mode 100644 index 784a366..0000000 --- a/vpn/java/com/android/server/vpn/L2tpService.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.net.vpn.L2tpProfile; - -import java.io.IOException; - -/** - * The service that manages the L2TP VPN connection. - */ -class L2tpService extends VpnService<L2tpProfile> { - @Override - protected void connect(String serverIp, String username, String password) - throws IOException { - L2tpProfile p = getProfile(); - getDaemons().startL2tp(serverIp, - (p.isSecretEnabled() ? p.getSecretString() : null), - username, password); - } -} diff --git a/vpn/java/com/android/server/vpn/PptpService.java b/vpn/java/com/android/server/vpn/PptpService.java deleted file mode 100644 index de12710..0000000 --- a/vpn/java/com/android/server/vpn/PptpService.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.net.vpn.PptpProfile; - -import java.io.IOException; - -/** - * The service that manages the PPTP VPN connection. - */ -class PptpService extends VpnService<PptpProfile> { - @Override - protected void connect(String serverIp, String username, String password) - throws IOException { - PptpProfile p = getProfile(); - getDaemons().startPptp(serverIp, username, password, - p.isEncryptionEnabled()); - } -} diff --git a/vpn/java/com/android/server/vpn/VpnConnectingError.java b/vpn/java/com/android/server/vpn/VpnConnectingError.java deleted file mode 100644 index 3c4ec7d..0000000 --- a/vpn/java/com/android/server/vpn/VpnConnectingError.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import java.io.IOException; - -/** - * Exception thrown when a connecting attempt fails. - */ -class VpnConnectingError extends IOException { - private int mErrorCode; - - VpnConnectingError(int errorCode) { - super("Connecting error: " + errorCode); - mErrorCode = errorCode; - } - - int getErrorCode() { - return mErrorCode; - } -} diff --git a/vpn/java/com/android/server/vpn/VpnDaemons.java b/vpn/java/com/android/server/vpn/VpnDaemons.java deleted file mode 100644 index 499195f..0000000 --- a/vpn/java/com/android/server/vpn/VpnDaemons.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.util.Log; - -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * A helper class for managing native VPN daemons. - */ -class VpnDaemons implements Serializable { - static final long serialVersionUID = 1L; - private final String TAG = VpnDaemons.class.getSimpleName(); - - private static final String MTPD = "mtpd"; - private static final String IPSEC = "racoon"; - - private static final String L2TP = "l2tp"; - private static final String L2TP_PORT = "1701"; - - private static final String PPTP = "pptp"; - private static final String PPTP_PORT = "1723"; - - private static final String VPN_LINKNAME = "vpn"; - private static final String PPP_ARGS_SEPARATOR = ""; - - private List<DaemonProxy> mDaemonList = new ArrayList<DaemonProxy>(); - - public DaemonProxy startL2tp(String serverIp, String secret, - String username, String password) throws IOException { - return startMtpd(L2TP, serverIp, L2TP_PORT, secret, username, password, - false); - } - - public DaemonProxy startPptp(String serverIp, String username, - String password, boolean encryption) throws IOException { - return startMtpd(PPTP, serverIp, PPTP_PORT, null, username, password, - encryption); - } - - public DaemonProxy startIpsecForL2tp(String serverIp, String pskKey) - throws IOException { - DaemonProxy ipsec = startDaemon(IPSEC); - ipsec.sendCommand(serverIp, L2TP_PORT, pskKey); - return ipsec; - } - - public DaemonProxy startIpsecForL2tp(String serverIp, String userKeyKey, - String userCertKey, String caCertKey) throws IOException { - DaemonProxy ipsec = startDaemon(IPSEC); - ipsec.sendCommand(serverIp, L2TP_PORT, userKeyKey, userCertKey, - caCertKey); - return ipsec; - } - - public synchronized void stopAll() { - new DaemonProxy(MTPD).stop(); - new DaemonProxy(IPSEC).stop(); - } - - public synchronized void closeSockets() { - for (DaemonProxy s : mDaemonList) s.closeControlSocket(); - } - - public synchronized boolean anyDaemonStopped() { - for (DaemonProxy s : mDaemonList) { - if (s.isStopped()) { - Log.w(TAG, " VPN daemon gone: " + s.getName()); - return true; - } - } - return false; - } - - public synchronized int getSocketError() { - for (DaemonProxy s : mDaemonList) { - int errCode = getResultFromSocket(s); - if (errCode != 0) return errCode; - } - return 0; - } - - private synchronized DaemonProxy startDaemon(String daemonName) - throws IOException { - DaemonProxy daemon = new DaemonProxy(daemonName); - mDaemonList.add(daemon); - daemon.start(); - return daemon; - } - - private int getResultFromSocket(DaemonProxy s) { - try { - return s.getResultFromSocket(); - } catch (IOException e) { - return -1; - } - } - - private DaemonProxy startMtpd(String protocol, - String serverIp, String port, String secret, String username, - String password, boolean encryption) throws IOException { - ArrayList<String> args = new ArrayList<String>(); - args.addAll(Arrays.asList(protocol, serverIp, port)); - if (secret != null) args.add(secret); - args.add(PPP_ARGS_SEPARATOR); - addPppArguments(args, serverIp, username, password, encryption); - - DaemonProxy mtpd = startDaemon(MTPD); - mtpd.sendCommand(args.toArray(new String[args.size()])); - return mtpd; - } - - private static void addPppArguments(ArrayList<String> args, String serverIp, - String username, String password, boolean encryption) - throws IOException { - args.addAll(Arrays.asList( - "linkname", VPN_LINKNAME, - "name", username, - "password", password, - "refuse-eap", "nodefaultroute", "usepeerdns", - "idle", "1800", - "mtu", "1400", - "mru", "1400")); - if (encryption) { - args.add("+mppe"); - } - } -} diff --git a/vpn/java/com/android/server/vpn/VpnService.java b/vpn/java/com/android/server/vpn/VpnService.java deleted file mode 100644 index 4966c06..0000000 --- a/vpn/java/com/android/server/vpn/VpnService.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.net.vpn.VpnManager; -import android.net.vpn.VpnProfile; -import android.net.vpn.VpnState; -import android.os.SystemProperties; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.R; - -import java.io.IOException; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.UnknownHostException; - -/** - * The service base class for managing a type of VPN connection. - */ -abstract class VpnService<E extends VpnProfile> { - private static final boolean DBG = true; - private static final int NOTIFICATION_ID = 1; - - private static final String DNS1 = "net.dns1"; - private static final String DNS2 = "net.dns2"; - private static final String VPN_DNS1 = "vpn.dns1"; - private static final String VPN_DNS2 = "vpn.dns2"; - private static final String VPN_STATUS = "vpn.status"; - private static final String VPN_IS_UP = "ok"; - private static final String VPN_IS_DOWN = "down"; - - private static final String REMOTE_IP = "net.ipremote"; - private static final String DNS_DOMAIN_SUFFICES = "net.dns.search"; - - private final String TAG = VpnService.class.getSimpleName(); - - E mProfile; - transient Context mContext; - - private VpnState mState = VpnState.IDLE; - private Throwable mError; - - // connection settings - private String mOriginalDns1; - private String mOriginalDns2; - private String mOriginalDomainSuffices; - private String mLocalIp; - private String mLocalIf; - - private long mStartTime; // VPN connection start time - - // for helping managing daemons - private VpnDaemons mDaemons = new VpnDaemons(); - - // for helping showing, updating notification - private transient NotificationHelper mNotification; - - /** - * Establishes a VPN connection with the specified username and password. - */ - protected abstract void connect(String serverIp, String username, - String password) throws IOException; - - /** - * Returns the daemons management class for this service object. - */ - protected VpnDaemons getDaemons() { - return mDaemons; - } - - /** - * Returns the VPN profile associated with the connection. - */ - protected E getProfile() { - return mProfile; - } - - /** - * Returns the IP address of the specified host name. - */ - protected String getIp(String hostName) throws IOException { - return InetAddress.getByName(hostName).getHostAddress(); - } - - void setContext(Context context, E profile) { - mProfile = profile; - mContext = context; - mNotification = new NotificationHelper(); - - if (VpnState.CONNECTED.equals(mState)) { - Log.i("VpnService", " recovered: " + mProfile.getName()); - startConnectivityMonitor(); - } - } - - VpnState getState() { - return mState; - } - - boolean isIdle() { - return (mState == VpnState.IDLE); - } - - synchronized boolean onConnect(String username, String password) { - try { - setState(VpnState.CONNECTING); - - mDaemons.stopAll(); - String serverIp = getIp(getProfile().getServerName()); - saveLocalIpAndInterface(serverIp); - onBeforeConnect(); - connect(serverIp, username, password); - waitUntilConnectedOrTimedout(); - return true; - } catch (Throwable e) { - onError(e); - return false; - } - } - - synchronized void onDisconnect() { - try { - Log.i(TAG, "disconnecting VPN..."); - setState(VpnState.DISCONNECTING); - mNotification.showDisconnect(); - - mDaemons.stopAll(); - } catch (Throwable e) { - Log.e(TAG, "onDisconnect()", e); - } finally { - onFinalCleanUp(); - } - } - - private void onError(Throwable error) { - // error may occur during or after connection setup - // and it may be due to one or all services gone - if (mError != null) { - Log.w(TAG, " multiple errors occur, record the last one: " - + error); - } - Log.e(TAG, "onError()", error); - mError = error; - onDisconnect(); - } - - private void onError(int errorCode) { - onError(new VpnConnectingError(errorCode)); - } - - - private void onBeforeConnect() throws IOException { - mNotification.disableNotification(); - - SystemProperties.set(VPN_DNS1, ""); - SystemProperties.set(VPN_DNS2, ""); - SystemProperties.set(VPN_STATUS, VPN_IS_DOWN); - if (DBG) { - Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS)); - } - } - - private void waitUntilConnectedOrTimedout() throws IOException { - sleep(2000); // 2 seconds - for (int i = 0; i < 80; i++) { - if (mState != VpnState.CONNECTING) { - break; - } else if (VPN_IS_UP.equals( - SystemProperties.get(VPN_STATUS))) { - onConnected(); - return; - } else { - int err = mDaemons.getSocketError(); - if (err != 0) { - onError(err); - return; - } - } - sleep(500); // 0.5 second - } - - if (mState == VpnState.CONNECTING) { - onError(new IOException("Connecting timed out")); - } - } - - private synchronized void onConnected() throws IOException { - if (DBG) Log.d(TAG, "onConnected()"); - - mDaemons.closeSockets(); - saveOriginalDns(); - saveAndSetDomainSuffices(); - - mStartTime = System.currentTimeMillis(); - - setState(VpnState.CONNECTED); - setVpnDns(); - - startConnectivityMonitor(); - } - - private synchronized void onFinalCleanUp() { - if (DBG) Log.d(TAG, "onFinalCleanUp()"); - - if (mState == VpnState.IDLE) return; - - // keep the notification when error occurs - if (!anyError()) mNotification.disableNotification(); - - restoreOriginalDns(); - restoreOriginalDomainSuffices(); - setState(VpnState.IDLE); - - SystemProperties.set(VPN_STATUS, VPN_IS_DOWN); - } - - private boolean anyError() { - return (mError != null); - } - - private void restoreOriginalDns() { - // restore only if they are not overridden - String vpnDns1 = SystemProperties.get(VPN_DNS1); - if (vpnDns1.equals(SystemProperties.get(DNS1))) { - Log.i(TAG, String.format("restore original dns prop: %s --> %s", - SystemProperties.get(DNS1), mOriginalDns1)); - Log.i(TAG, String.format("restore original dns prop: %s --> %s", - SystemProperties.get(DNS2), mOriginalDns2)); - SystemProperties.set(DNS1, mOriginalDns1); - SystemProperties.set(DNS2, mOriginalDns2); - } - } - - private void saveOriginalDns() { - mOriginalDns1 = SystemProperties.get(DNS1); - mOriginalDns2 = SystemProperties.get(DNS2); - Log.i(TAG, String.format("save original dns prop: %s, %s", - mOriginalDns1, mOriginalDns2)); - } - - private void setVpnDns() { - String vpnDns1 = SystemProperties.get(VPN_DNS1); - String vpnDns2 = SystemProperties.get(VPN_DNS2); - SystemProperties.set(DNS1, vpnDns1); - SystemProperties.set(DNS2, vpnDns2); - Log.i(TAG, String.format("set vpn dns prop: %s, %s", - vpnDns1, vpnDns2)); - } - - private void saveAndSetDomainSuffices() { - mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES); - Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices); - String list = mProfile.getDomainSuffices(); - if (!TextUtils.isEmpty(list)) { - SystemProperties.set(DNS_DOMAIN_SUFFICES, list); - } - } - - private void restoreOriginalDomainSuffices() { - Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices); - SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices); - } - - private void setState(VpnState newState) { - mState = newState; - broadcastConnectivity(newState); - } - - private void broadcastConnectivity(VpnState s) { - VpnManager m = new VpnManager(mContext); - Throwable err = mError; - if ((s == VpnState.IDLE) && (err != null)) { - if (err instanceof UnknownHostException) { - m.broadcastConnectivity(mProfile.getName(), s, - VpnManager.VPN_ERROR_UNKNOWN_SERVER); - } else if (err instanceof VpnConnectingError) { - m.broadcastConnectivity(mProfile.getName(), s, - ((VpnConnectingError) err).getErrorCode()); - } else if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) { - m.broadcastConnectivity(mProfile.getName(), s, - VpnManager.VPN_ERROR_CONNECTION_LOST); - } else { - m.broadcastConnectivity(mProfile.getName(), s, - VpnManager.VPN_ERROR_CONNECTION_FAILED); - } - } else { - m.broadcastConnectivity(mProfile.getName(), s); - } - } - - private void startConnectivityMonitor() { - new Thread(new Runnable() { - public void run() { - Log.i(TAG, "VPN connectivity monitor running"); - try { - mNotification.update(mStartTime); // to pop up notification - for (int i = 10; ; i--) { - long now = System.currentTimeMillis(); - - boolean heavyCheck = i == 0; - synchronized (VpnService.this) { - if (mState != VpnState.CONNECTED) break; - mNotification.update(now); - - if (heavyCheck) { - i = 10; - if (checkConnectivity()) checkDns(); - } - long t = 1000L - System.currentTimeMillis() + now; - if (t > 100L) VpnService.this.wait(t); - } - } - } catch (InterruptedException e) { - onError(e); - } - Log.i(TAG, "VPN connectivity monitor stopped"); - } - }).start(); - } - - private void saveLocalIpAndInterface(String serverIp) throws IOException { - DatagramSocket s = new DatagramSocket(); - int port = 80; // arbitrary - s.connect(InetAddress.getByName(serverIp), port); - InetAddress localIp = s.getLocalAddress(); - mLocalIp = localIp.getHostAddress(); - NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp); - mLocalIf = (localIf == null) ? null : localIf.getName(); - if (TextUtils.isEmpty(mLocalIf)) { - throw new IOException("Local interface is empty!"); - } - if (DBG) { - Log.d(TAG, " Local IP: " + mLocalIp + ", if: " + mLocalIf); - } - } - - // returns false if vpn connectivity is broken - private boolean checkConnectivity() { - if (mDaemons.anyDaemonStopped() || isLocalIpChanged()) { - onError(new IOException("Connectivity lost")); - return false; - } else { - return true; - } - } - - private void checkDns() { - String dns1 = SystemProperties.get(DNS1); - String vpnDns1 = SystemProperties.get(VPN_DNS1); - if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) { - // dhcp expires? - setVpnDns(); - } - } - - private boolean isLocalIpChanged() { - try { - InetAddress localIp = InetAddress.getByName(mLocalIp); - NetworkInterface localIf = - NetworkInterface.getByInetAddress(localIp); - if (localIf == null || !mLocalIf.equals(localIf.getName())) { - Log.w(TAG, " local If changed from " + mLocalIf - + " to " + localIf); - return true; - } else { - return false; - } - } catch (IOException e) { - Log.w(TAG, "isLocalIpChanged()", e); - return true; - } - } - - protected void sleep(int ms) { - try { - Thread.currentThread().sleep(ms); - } catch (InterruptedException e) { - } - } - - // Helper class for showing, updating notification. - private class NotificationHelper { - private NotificationManager mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - private Notification mNotification = - new Notification(R.drawable.vpn_connected, null, 0L); - private PendingIntent mPendingIntent = PendingIntent.getActivity( - mContext, 0, - new VpnManager(mContext).createSettingsActivityIntent(), 0); - private String mConnectedTitle; - - void update(long now) { - Notification n = mNotification; - if (now == mStartTime) { - // to pop up the notification for the first time - n.when = mStartTime; - n.tickerText = mConnectedTitle = getNotificationTitle(true); - } else { - n.tickerText = null; - } - n.setLatestEventInfo(mContext, mConnectedTitle, - getConnectedNotificationMessage(now), - mPendingIntent); - n.flags |= Notification.FLAG_NO_CLEAR; - n.flags |= Notification.FLAG_ONGOING_EVENT; - enableNotification(n); - } - - void showDisconnect() { - String title = getNotificationTitle(false); - Notification n = new Notification(R.drawable.vpn_disconnected, - title, System.currentTimeMillis()); - n.setLatestEventInfo(mContext, title, - getDisconnectedNotificationMessage(), - mPendingIntent); - n.flags |= Notification.FLAG_AUTO_CANCEL; - disableNotification(); - enableNotification(n); - } - - void disableNotification() { - mNotificationManager.cancel(NOTIFICATION_ID); - } - - private void enableNotification(Notification n) { - mNotificationManager.notify(NOTIFICATION_ID, n); - } - - private String getNotificationTitle(boolean connected) { - String formatString = connected - ? mContext.getString( - R.string.vpn_notification_title_connected) - : mContext.getString( - R.string.vpn_notification_title_disconnected); - return String.format(formatString, mProfile.getName()); - } - - private String getFormattedTime(int duration) { - int hours = duration / 3600; - StringBuilder sb = new StringBuilder(); - if (hours > 0) sb.append(hours).append(':'); - sb.append(String.format("%02d:%02d", (duration % 3600 / 60), - (duration % 60))); - return sb.toString(); - } - - private String getConnectedNotificationMessage(long now) { - return getFormattedTime((int) (now - mStartTime) / 1000); - } - - private String getDisconnectedNotificationMessage() { - return mContext.getString( - R.string.vpn_notification_hint_disconnected); - } - } -} diff --git a/vpn/java/com/android/server/vpn/VpnServiceBinder.java b/vpn/java/com/android/server/vpn/VpnServiceBinder.java deleted file mode 100644 index c474ff9..0000000 --- a/vpn/java/com/android/server/vpn/VpnServiceBinder.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.net.vpn.IVpnService; -import android.net.vpn.L2tpIpsecProfile; -import android.net.vpn.L2tpIpsecPskProfile; -import android.net.vpn.L2tpProfile; -import android.net.vpn.PptpProfile; -import android.net.vpn.VpnManager; -import android.net.vpn.VpnProfile; -import android.net.vpn.VpnState; -import android.util.Log; - -/** - * The service class for managing a VPN connection. It implements the - * {@link IVpnService} binder interface. - */ -public class VpnServiceBinder extends IVpnService.Stub { - private static final String TAG = VpnServiceBinder.class.getSimpleName(); - private static final boolean DBG = true; - - // The actual implementation is delegated to the VpnService class. - private VpnService<? extends VpnProfile> mService; - - private Context mContext; - - public VpnServiceBinder(Context context) { - mContext = context; - } - - @Override - public synchronized boolean connect(VpnProfile p, final String username, - final String password) { - if ((mService != null) && !mService.isIdle()) return false; - final VpnService s = mService = createService(p); - - new Thread(new Runnable() { - public void run() { - s.onConnect(username, password); - } - }).start(); - return true; - } - - @Override - public synchronized void disconnect() { - if (mService == null) return; - final VpnService s = mService; - mService = null; - - new Thread(new Runnable() { - public void run() { - s.onDisconnect(); - } - }).start(); - } - - @Override - public synchronized String getState(VpnProfile p) { - if ((mService == null) - || (!p.getName().equals(mService.mProfile.getName()))) { - return VpnState.IDLE.toString(); - } else { - return mService.getState().toString(); - } - } - - @Override - public synchronized boolean isIdle() { - return (mService == null || mService.isIdle()); - } - - private VpnService<? extends VpnProfile> createService(VpnProfile p) { - switch (p.getType()) { - case L2TP: - L2tpService l2tp = new L2tpService(); - l2tp.setContext(mContext, (L2tpProfile) p); - return l2tp; - - case PPTP: - PptpService pptp = new PptpService(); - pptp.setContext(mContext, (PptpProfile) p); - return pptp; - - case L2TP_IPSEC_PSK: - L2tpIpsecPskService psk = new L2tpIpsecPskService(); - psk.setContext(mContext, (L2tpIpsecPskProfile) p); - return psk; - - case L2TP_IPSEC: - L2tpIpsecService l2tpIpsec = new L2tpIpsecService(); - l2tpIpsec.setContext(mContext, (L2tpIpsecProfile) p); - return l2tpIpsec; - - default: - return null; - } - } -} diff --git a/vpn/tests/vpntests/Android.mk b/vpn/tests/vpntests/Android.mk deleted file mode 100644 index a19fb56..0000000 --- a/vpn/tests/vpntests/Android.mk +++ /dev/null @@ -1,14 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_PACKAGE_NAME := FrameworksVpnTests - -include $(BUILD_PACKAGE) - diff --git a/vpn/tests/vpntests/AndroidManifest.xml b/vpn/tests/vpntests/AndroidManifest.xml deleted file mode 100644 index d8405f6..0000000 --- a/vpn/tests/vpntests/AndroidManifest.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.vpntests"> - <uses-permission android:name="android.permission.RECEIVE_SMS"/> - <uses-permission android:name="android.permission.INTERNET" /> - <uses-permission android:name="android.permission.READ_CONTACTS" /> - <uses-permission android:name="android.permission.WRITE_CONTACTS" /> - <uses-permission android:name="android.permission.WAKE_LOCK" /> - <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> - <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" /> - <uses-permission android:name="android.permission.BROADCAST_STICKY" /> - - <application> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation - android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.android.frameworks.vpntests" - android:label="Frameworks VPN Tests" /> -</manifest> diff --git a/vpn/tests/vpntests/src/android/net/vpn/VpnTest.java b/vpn/tests/vpntests/src/android/net/vpn/VpnTest.java deleted file mode 100755 index 46a57d3..0000000 --- a/vpn/tests/vpntests/src/android/net/vpn/VpnTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.vpn; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.vpn.L2tpProfile; -import android.net.vpn.L2tpIpsecProfile; -import android.net.vpn.L2tpIpsecPskProfile; -import android.net.vpn.PptpProfile; -import android.net.vpn.VpnManager; -import android.net.vpn.VpnProfile; -import android.net.vpn.VpnState; -import android.net.vpn.VpnType; -import android.os.ConditionVariable; -import android.os.Parcel; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.text.TextUtils; - -/** - * Unit test class to test VPN api - * Use the below command to run the vpn unit test only - * runtest vpntest or - * adb shell am instrument -e class 'com.android.unit_tests.VpnTest' - * -w com.android.unit_tests/android.test.InstrumentationTestRunner - */ -public class VpnTest extends AndroidTestCase { - private static final String NAME = "a name"; - private static final String SERVER_NAME = "a server name"; - private static final String ID = "some id"; - private static final String SUFFICES = "some suffices"; - private static final String ROUTES = "some routes"; - private static final String SAVED_NAME = "some name"; - - @Override - public void setUp() { - } - - @Override - public void tearDown() { - } - - @SmallTest - public void testVpnType() { - testVpnType(VpnType.L2TP); - testVpnType(VpnType.L2TP_IPSEC); - testVpnType(VpnType.L2TP_IPSEC_PSK); - testVpnType(VpnType.PPTP); - } - - @SmallTest - public void testVpnProfile() { - VpnState state = VpnState.CONNECTING; - testVpnProfile(createTestProfile(state), state); - } - - @SmallTest - public void testGetType() { - assertEquals(VpnType.L2TP, new L2tpProfile().getType()); - assertEquals(VpnType.L2TP_IPSEC, new L2tpIpsecProfile().getType()); - assertEquals(VpnType.L2TP_IPSEC_PSK, - new L2tpIpsecPskProfile().getType()); - assertEquals(VpnType.PPTP, new PptpProfile().getType()); - } - - @SmallTest - public void testVpnTypes() { - assertTrue(VpnManager.getSupportedVpnTypes().length > 0); - } - - @SmallTest - public void testGetTypeFromManager() { - VpnManager m = new VpnManager(getContext()); - VpnType[] types = VpnManager.getSupportedVpnTypes(); - for (VpnType t : types) { - assertEquals(t, m.createVpnProfile(t).getType()); - } - } - - @SmallTest - public void testParcelable() { - VpnProfile p = createTestProfile(VpnState.CONNECTED); - Parcel parcel = Parcel.obtain(); - p.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - - // VpnState is transient and not saved in the parcel - testVpnProfile(VpnProfile.CREATOR.createFromParcel(parcel), null); - } - - @SmallTest - public void testReceiver() { - final String profileName = "whatever"; - final VpnState state = VpnState.DISCONNECTING; - final ConditionVariable cv = new ConditionVariable(); - cv.close(); - BroadcastReceiver r = new BroadcastReceiver() { - public void onReceive(Context c, Intent i) { - assertEquals(profileName, - i.getStringExtra(VpnManager.BROADCAST_PROFILE_NAME)); - assertEquals(state, i.getSerializableExtra( - VpnManager.BROADCAST_CONNECTION_STATE)); - cv.open(); - } - }; - - VpnManager m = new VpnManager(getContext()); - m.registerConnectivityReceiver(r); - m.broadcastConnectivity(profileName, state); - - // fail it if onReceive() doesn't get executed in 5 sec - assertTrue(cv.block(5000)); - } - - private void testVpnType(VpnType type) { - assertFalse(TextUtils.isEmpty(type.getDisplayName())); - assertNotNull(type.getProfileClass()); - } - - private VpnProfile createTestProfile(VpnState state) { - VpnProfile p = new L2tpProfile(); - p.setName(NAME); - p.setServerName(SERVER_NAME); - p.setId(ID); - p.setDomainSuffices(SUFFICES); - p.setRouteList(ROUTES); - p.setSavedUsername(SAVED_NAME); - p.setState(state); - return p; - } - - private void testVpnProfile(VpnProfile p, VpnState state) { - assertEquals(NAME, p.getName()); - assertEquals(SERVER_NAME, p.getServerName()); - assertEquals(ID, p.getId()); - assertEquals(SUFFICES, p.getDomainSuffices()); - assertEquals(ROUTES, p.getRouteList()); - assertEquals(SAVED_NAME, p.getSavedUsername()); - if (state != null) assertEquals(state, p.getState()); - } -} |