1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "EphemeralStorage"
18//#define LOG_NDEBUG 0
19
20#include <android-base/logging.h>
21
22#include "EphemeralStorage.h"
23
24using ::android::hardware::hidl_string;
25using ::android::hardware::hidl_vec;
26
27namespace android {
28
29EphemeralStorage::EphemeralStorage() {
30}
31
32EphemeralStorage::~EphemeralStorage() {
33    CHECK(mItems.empty())
34        << "All item storage should have been released by now.";
35}
36
37hidl_string *EphemeralStorage::allocStringArray(size_t size) {
38    Item item;
39    item.mType = TYPE_STRING_ARRAY;
40    item.mObj = NULL;
41    item.mPtr = new hidl_string[size];
42    mItems.push_back(item);
43
44    return static_cast<hidl_string *>(item.mPtr);
45}
46
47void *EphemeralStorage::allocTemporaryStorage(size_t size) {
48    Item item;
49    item.mType = TYPE_STORAGE;
50    item.mObj = NULL;
51    item.mPtr = malloc(size);
52    mItems.push_back(item);
53
54    return item.mPtr;
55}
56
57const hidl_string *EphemeralStorage::allocTemporaryString(
58        JNIEnv *env, jstring stringObj) {
59    jstring obj = (jstring)env->NewGlobalRef(stringObj);
60    const char *val = env->GetStringUTFChars(obj, NULL);
61
62    Item item;
63    item.mType = TYPE_STRING;
64    item.mObj = obj;
65    item.mPtr = (void *)val;
66    mItems.push_back(item);
67
68    hidl_string *s = allocStringArray(1 /* size */);
69    s->setToExternal((char *)val, strlen(val));
70
71    return s;
72}
73
74#define DEFINE_ALLOC_VECTOR_METHODS(Suffix,Type,NewType)                       \
75const hidl_vec<Type> *EphemeralStorage::allocTemporary ## Suffix ## Vector(    \
76        JNIEnv *env, Type ## Array arrayObj) {                                 \
77    Type ## Array obj = (Type ## Array)env->NewGlobalRef(arrayObj);            \
78    jsize len = env->GetArrayLength(obj);                                      \
79    const Type *val = env->Get ## NewType ## ArrayElements(obj, NULL);         \
80                                                                               \
81    Item item;                                                                 \
82    item.mType = TYPE_ ## Suffix ## _ARRAY;                                    \
83    item.mObj = obj;                                                           \
84    item.mPtr = (void *)val;                                                   \
85    mItems.push_back(item);                                                    \
86                                                                               \
87    void *vecPtr = allocTemporaryStorage(sizeof(hidl_vec<Type>));              \
88                                                                               \
89    hidl_vec<Type> *vec = new (vecPtr) hidl_vec<Type>;                         \
90    vec->setToExternal(const_cast<Type *>(val), len);                          \
91                                                                               \
92    return vec;                                                                \
93}
94
95DEFINE_ALLOC_VECTOR_METHODS(Int8,jbyte,Byte)
96DEFINE_ALLOC_VECTOR_METHODS(Int16,jshort,Short)
97DEFINE_ALLOC_VECTOR_METHODS(Int32,jint,Int)
98DEFINE_ALLOC_VECTOR_METHODS(Int64,jlong,Long)
99DEFINE_ALLOC_VECTOR_METHODS(Float,jfloat,Float)
100DEFINE_ALLOC_VECTOR_METHODS(Double,jdouble,Double)
101
102#define DEFINE_RELEASE_ARRAY_CASE(Suffix,Type,NewType)                         \
103            case TYPE_ ## Suffix ## _ARRAY:                                    \
104            {                                                                  \
105                env->Release ## NewType ## ArrayElements(                      \
106                        (Type ## Array)item.mObj,                              \
107                        (Type *)item.mPtr,                                     \
108                        0 /* mode */);                                         \
109                                                                               \
110                env->DeleteGlobalRef(item.mObj);                               \
111                break;                                                         \
112            }
113
114__attribute__((no_sanitize("unsigned-integer-overflow")))
115void EphemeralStorage::release(JNIEnv *env) {
116    for (size_t i = mItems.size(); i--;) {
117        const Item &item = mItems[i];
118
119        switch (item.mType) {
120            case TYPE_STRING_ARRAY:
121            {
122                delete[] static_cast<hidl_string *>(item.mPtr);
123                break;
124            }
125
126            case TYPE_STORAGE:
127            {
128                free(item.mPtr);
129                break;
130            }
131
132            case TYPE_STRING:
133            {
134                env->ReleaseStringUTFChars(
135                        (jstring)item.mObj, (const char *)item.mPtr);
136
137                env->DeleteGlobalRef(item.mObj);
138                break;
139            }
140
141            DEFINE_RELEASE_ARRAY_CASE(Int8,jbyte,Byte)
142            DEFINE_RELEASE_ARRAY_CASE(Int16,jshort,Short)
143            DEFINE_RELEASE_ARRAY_CASE(Int32,jint,Int)
144            DEFINE_RELEASE_ARRAY_CASE(Int64,jlong,Long)
145            DEFINE_RELEASE_ARRAY_CASE(Float,jfloat,Float)
146            DEFINE_RELEASE_ARRAY_CASE(Double,jdouble,Double)
147
148            default:
149                CHECK(!"Should not be here");
150        }
151    }
152
153    mItems.clear();
154}
155
156}  // namespace android
157
158