| /* | |
| * Copyright (C) 2014 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 H_ATTRIBUTE_FINDER | |
| #define H_ATTRIBUTE_FINDER | |
| #include <stdint.h> | |
| #include <utils/KeyedVector.h> | |
| namespace android { | |
| static inline uint32_t getPackage(uint32_t attr) { | |
| return attr >> 24; | |
| } | |
| /** | |
| * A helper class to search linearly for the requested | |
| * attribute, maintaining it's position and optimizing for | |
| * the case that subsequent searches will involve an attribute with | |
| * a higher attribute ID. | |
| * | |
| * In the case that a subsequent attribute has a different package ID, | |
| * its resource ID may not be larger than the preceding search, so | |
| * back tracking is supported for this case. This | |
| * back tracking requirement is mainly for shared library | |
| * resources, whose package IDs get assigned at runtime | |
| * and thus attributes from a shared library may | |
| * be out of order. | |
| * | |
| * We make two assumptions about the order of attributes: | |
| * 1) The input has the same sorting rules applied to it as | |
| * the attribute data contained by this class. | |
| * 2) Attributes are grouped by package ID. | |
| * 3) Among attributes with the same package ID, the attributes are | |
| * sorted by increasing resource ID. | |
| * | |
| * Ex: 02010000, 02010001, 010100f4, 010100f5, 0x7f010001, 07f010003 | |
| * | |
| * The total order of attributes (including package ID) can not be linear | |
| * as shared libraries get assigned dynamic package IDs at runtime, which | |
| * may break the sort order established at build time. | |
| */ | |
| template <typename Derived, typename Iterator> | |
| class BackTrackingAttributeFinder { | |
| public: | |
| BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end); | |
| Iterator find(uint32_t attr); | |
| private: | |
| void jumpToClosestAttribute(uint32_t packageId); | |
| void markCurrentPackageId(uint32_t packageId); | |
| bool mFirstTime; | |
| Iterator mBegin; | |
| Iterator mEnd; | |
| Iterator mCurrent; | |
| Iterator mLargest; | |
| uint32_t mLastPackageId; | |
| uint32_t mCurrentAttr; | |
| // Package Offsets (best-case, fast look-up). | |
| Iterator mFrameworkStart; | |
| Iterator mAppStart; | |
| // Worst case, we have shared-library resources. | |
| KeyedVector<uint32_t, Iterator> mPackageOffsets; | |
| }; | |
| template <typename Derived, typename Iterator> inline | |
| BackTrackingAttributeFinder<Derived, Iterator>::BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end) | |
| : mFirstTime(true) | |
| , mBegin(begin) | |
| , mEnd(end) | |
| , mCurrent(begin) | |
| , mLargest(begin) | |
| , mLastPackageId(0) | |
| , mCurrentAttr(0) | |
| , mFrameworkStart(end) | |
| , mAppStart(end) { | |
| } | |
| template <typename Derived, typename Iterator> | |
| void BackTrackingAttributeFinder<Derived, Iterator>::jumpToClosestAttribute(const uint32_t packageId) { | |
| switch (packageId) { | |
| case 0x01: | |
| mCurrent = mFrameworkStart; | |
| break; | |
| case 0x7f: | |
| mCurrent = mAppStart; | |
| break; | |
| default: { | |
| ssize_t idx = mPackageOffsets.indexOfKey(packageId); | |
| if (idx >= 0) { | |
| // We have seen this package ID before, so jump to the first | |
| // attribute with this package ID. | |
| mCurrent = mPackageOffsets[idx]; | |
| } else { | |
| mCurrent = mEnd; | |
| } | |
| break; | |
| } | |
| } | |
| // We have never seen this package ID yet, so jump to the | |
| // latest/largest index we have processed so far. | |
| if (mCurrent == mEnd) { | |
| mCurrent = mLargest; | |
| } | |
| if (mCurrent != mEnd) { | |
| mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent); | |
| } | |
| } | |
| template <typename Derived, typename Iterator> | |
| void BackTrackingAttributeFinder<Derived, Iterator>::markCurrentPackageId(const uint32_t packageId) { | |
| switch (packageId) { | |
| case 0x01: | |
| mFrameworkStart = mCurrent; | |
| break; | |
| case 0x7f: | |
| mAppStart = mCurrent; | |
| break; | |
| default: | |
| mPackageOffsets.add(packageId, mCurrent); | |
| break; | |
| } | |
| } | |
| template <typename Derived, typename Iterator> | |
| Iterator BackTrackingAttributeFinder<Derived, Iterator>::find(uint32_t attr) { | |
| if (!(mBegin < mEnd)) { | |
| return mEnd; | |
| } | |
| if (mFirstTime) { | |
| // One-time initialization. We do this here instead of the constructor | |
| // because the derived class we access in getAttribute() may not be | |
| // fully constructed. | |
| mFirstTime = false; | |
| mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mBegin); | |
| mLastPackageId = getPackage(mCurrentAttr); | |
| markCurrentPackageId(mLastPackageId); | |
| } | |
| // Looking for the needle (attribute we're looking for) | |
| // in the haystack (the attributes we're searching through) | |
| const uint32_t needlePackageId = getPackage(attr); | |
| if (mLastPackageId != needlePackageId) { | |
| jumpToClosestAttribute(needlePackageId); | |
| mLastPackageId = needlePackageId; | |
| } | |
| // Walk through the xml attributes looking for the requested attribute. | |
| while (mCurrent != mEnd) { | |
| const uint32_t haystackPackageId = getPackage(mCurrentAttr); | |
| if (needlePackageId == haystackPackageId && attr < mCurrentAttr) { | |
| // The attribute we are looking was not found. | |
| break; | |
| } | |
| const uint32_t prevAttr = mCurrentAttr; | |
| // Move to the next attribute in the XML. | |
| ++mCurrent; | |
| if (mCurrent != mEnd) { | |
| mCurrentAttr = static_cast<const Derived*>(this)->getAttribute(mCurrent); | |
| const uint32_t newHaystackPackageId = getPackage(mCurrentAttr); | |
| if (haystackPackageId != newHaystackPackageId) { | |
| // We've moved to the next group of attributes | |
| // with a new package ID, so we should record | |
| // the offset of this new package ID. | |
| markCurrentPackageId(newHaystackPackageId); | |
| } | |
| } | |
| if (mCurrent > mLargest) { | |
| // We've moved past the latest attribute we've | |
| // seen. | |
| mLargest = mCurrent; | |
| } | |
| if (attr == prevAttr) { | |
| // We found the attribute we were looking for. | |
| return mCurrent - 1; | |
| } | |
| } | |
| return mEnd; | |
| } | |
| } // namespace android | |
| #endif // H_ATTRIBUTE_FINDER |