/* * Copyright (C) 2015 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 "KeystoreOperation" #include "operation.h" #include <algorithm> #include <android-base/logging.h> #include <mutex> namespace keystore { OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient) : mDeathRecipient(deathRecipient) {} sp<IBinder> OperationMap::addOperation(uint64_t handle, uint64_t keyid, KeyPurpose purpose, const sp<Keymaster>& dev, const sp<IBinder>& appToken, KeyCharacteristics&& characteristics, const hidl_vec<KeyParameter>& params, bool pruneable) { sp<IBinder> token = new ::android::BBinder(); mMap.emplace(token, std::make_shared<Operation>(handle, keyid, purpose, dev, std::move(characteristics), appToken, params)); if (pruneable) mLru.push_back(token); if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) appToken->linkToDeath(mDeathRecipient); mAppTokenMap[appToken].push_back(token); return token; } std::shared_ptr<Operation> OperationMap::getOperation(const sp<IBinder>& token) { auto entry = mMap.find(token); if (entry == mMap.end()) return {}; auto op = entry->second; updateLru(token); return op; } void OperationMap::updateLru(const sp<IBinder>& token) { auto lruEntry = std::find(mLru.begin(), mLru.end(), token); if (lruEntry != mLru.end()) { mLru.erase(lruEntry); mLru.push_back(token); } } std::shared_ptr<Operation> OperationMap::removeOperation(const sp<IBinder>& token, bool wasSuccessful) { auto entry = mMap.find(token); if (entry == mMap.end()) return {}; auto op = entry->second; operationUploader.uploadOpAsProto(*op, wasSuccessful); mMap.erase(entry); auto lruEntry = std::find(mLru.begin(), mLru.end(), token); if (lruEntry != mLru.end()) mLru.erase(lruEntry); removeOperationTracking(token, op->appToken); return op; } void OperationMap::removeOperationTracking(const sp<IBinder>& token, const sp<IBinder>& appToken) { auto appEntry = mAppTokenMap.find(appToken); if (appEntry == mAppTokenMap.end()) { ALOGE("Entry for %p contains unmapped application token %p", token.get(), appToken.get()); return; } auto tokenEntry = std::find(appEntry->second.begin(), appEntry->second.end(), token); appEntry->second.erase(tokenEntry); // Stop listening for death if all operations tied to the token have finished. if (appEntry->second.size() == 0) { appToken->unlinkToDeath(mDeathRecipient); mAppTokenMap.erase(appEntry); } } sp<IBinder> OperationMap::getOldestPruneableOperation() { if (mLru.size() == 0) return {}; return {mLru.front()}; } std::vector<sp<IBinder>> OperationMap::getOperationsForToken(const sp<IBinder>& appToken) { auto appEntry = mAppTokenMap.find(appToken); if (appEntry == mAppTokenMap.end()) return {}; return appEntry->second; } } // namespace keystore