1 #include <android/binder_auto_utils.h>
2 #include <android/binder_ibinder.h>
3 #include <android/binder_status.h>
4
5 #include <cstdint>
6 #include <cstdlib>
7 #include <memory>
8 #include <optional>
9 #include <vector>
10
11 #include "aidl/com/android/isolated_storage_service/BnIcingSearchEngine.h"
12 #include "aidl/com/android/isolated_storage_service/BnIsolatedStorageService.h"
13 #include <vm_payload.h>
14 #include "icing/icing-search-engine.h"
15 #include "icing/proto/blob.pb.h"
16 #include "icing/proto/document.pb.h"
17 #include "icing/proto/initialize.pb.h"
18 #include "icing/proto/schema.pb.h"
19 #include "icing/proto/scoring.pb.h"
20 #include "icing/proto/search.pb.h"
21 #include "icing/proto/status.pb.h"
22 #include "icing/proto/storage.pb.h"
23 #include "icing/proto/term.pb.h"
24 #include "icing/proto/usage.pb.h"
25 #include "icing/util/logging.h"
26 #include "macros.h"
27
28 namespace {
29
30 using ::aidl::com::android::isolated_storage_service::BnIcingSearchEngine;
31 using ::aidl::com::android::isolated_storage_service::BnIsolatedStorageService;
32 using ::icing::lib::BatchPutResultProto;
33 using ::icing::lib::BlobProto;
34 using ::icing::lib::DebugInfoResultProto;
35 using ::icing::lib::DebugInfoVerbosity;
36 using ::icing::lib::DeleteByNamespaceResultProto;
37 using ::icing::lib::DeleteByQueryResultProto;
38 using ::icing::lib::DeleteBySchemaTypeResultProto;
39 using ::icing::lib::DeleteResultProto;
40 using ::icing::lib::DocumentProto;
41 using ::icing::lib::GetAllNamespacesResultProto;
42 using ::icing::lib::GetOptimizeInfoResultProto;
43 using ::icing::lib::GetResultProto;
44 using ::icing::lib::GetResultSpecProto;
45 using ::icing::lib::GetSchemaResultProto;
46 using ::icing::lib::GetSchemaTypeResultProto;
47 using ::icing::lib::IcingSearchEngine;
48 using ::icing::lib::IcingSearchEngineOptions;
49 using ::icing::lib::InitializeResultProto;
50 using ::icing::lib::OptimizeResultProto;
51 using ::icing::lib::PersistToDiskResultProto;
52 using ::icing::lib::PersistType;
53 using ::icing::lib::PutDocumentRequest;
54 using ::icing::lib::PutResultProto;
55 using ::icing::lib::ReportUsageResultProto;
56 using ::icing::lib::ResetResultProto;
57 using ::icing::lib::ResultSpecProto;
58 using ::icing::lib::SchemaProto;
59 using ::icing::lib::ScoringSpecProto;
60 using ::icing::lib::SearchResultProto;
61 using ::icing::lib::SearchSpecProto;
62 using ::icing::lib::SetSchemaResultProto;
63 using ::icing::lib::StatusProto;
64 using ::icing::lib::StorageInfoResultProto;
65 using ::icing::lib::SuggestionResponse;
66 using ::icing::lib::SuggestionSpecProto;
67 using ::icing::lib::TermMatchType;
68 using ::icing::lib::UsageReport;
69 using BlobHandleProto = ::icing::lib::PropertyProto::BlobHandleProto;
70 using ::icing::lib::INFO;
71 using ::ndk::ScopedAStatus;
72
73 // This class implements the AIDL interface for the Icing connection.
74 class IcingConnectionImpl
75 : public aidl::com::android::isolated_storage_service::BnIcingSearchEngine {
76 public:
IcingConnectionImpl(uint32_t uid)77 explicit IcingConnectionImpl(uint32_t uid) : uid_(uid) {}
78
initialize(const std::vector<uint8_t> & icing_search_engine_options_proto,std::optional<std::vector<uint8_t>> * initialize_result_proto)79 ScopedAStatus initialize(
80 const std::vector<uint8_t>& icing_search_engine_options_proto,
81 std::optional<std::vector<uint8_t>>* initialize_result_proto) {
82 IcingSearchEngineOptions options;
83 DESERIALIZE_OR_RETURN(icing_search_engine_options_proto, options);
84 options.set_base_dir(std::string(AVmPayload_getEncryptedStoragePath()) +
85 "/" + std::to_string(uid_) + "/" + options.base_dir());
86 icing_ = std::make_unique<IcingSearchEngine>(options);
87 InitializeResultProto initialize_result = icing_->Initialize();
88 SERIALIZE_AND_RETURN_ASTATUS(initialize_result, initialize_result_proto);
89 }
90
close()91 ScopedAStatus close() {
92 CHECK_ICING_INIT(icing_);
93 ICING_LOG(INFO) << "IsolatedStorageService closing Icing connection.";
94 icing_->PersistToDisk(icing::lib::PersistType::FULL);
95 return ScopedAStatus::ok();
96 }
97
reset(std::optional<std::vector<uint8_t>> * reset_result_proto)98 ScopedAStatus reset(std::optional<std::vector<uint8_t>>* reset_result_proto) {
99 CHECK_ICING_INIT(icing_);
100 ResetResultProto reset_result = icing_->Reset();
101 SERIALIZE_AND_RETURN_ASTATUS(reset_result, reset_result_proto);
102 }
103
setSchema(const std::vector<uint8_t> & schema_proto,bool ignore_errors_and_delete_documents,std::optional<std::vector<uint8_t>> * set_schema_result_proto)104 ScopedAStatus setSchema(
105 const std::vector<uint8_t>& schema_proto,
106 bool ignore_errors_and_delete_documents,
107 std::optional<std::vector<uint8_t>>* set_schema_result_proto) {
108 CHECK_ICING_INIT(icing_);
109
110 SchemaProto schema;
111 DESERIALIZE_OR_RETURN(schema_proto, schema)
112
113 SetSchemaResultProto set_schema_result =
114 icing_->SetSchema(schema, ignore_errors_and_delete_documents);
115 SERIALIZE_AND_RETURN_ASTATUS(set_schema_result, set_schema_result_proto);
116 }
117
getSchema(std::optional<std::vector<uint8_t>> * get_schema_result_proto)118 ScopedAStatus getSchema(
119 std::optional<std::vector<uint8_t>>* get_schema_result_proto) {
120 CHECK_ICING_INIT(icing_);
121
122 GetSchemaResultProto schema = icing_->GetSchema();
123 SERIALIZE_AND_RETURN_ASTATUS(schema, get_schema_result_proto);
124 }
125
getSchemaForDatabase(const std::string & database,std::optional<std::vector<uint8_t>> * get_schema_result_proto)126 ScopedAStatus getSchemaForDatabase(
127 const std::string& database,
128 std::optional<std::vector<uint8_t>>* get_schema_result_proto) {
129 CHECK_ICING_INIT(icing_);
130 GetSchemaResultProto schema = icing_->GetSchema(database);
131 SERIALIZE_AND_RETURN_ASTATUS(schema, get_schema_result_proto);
132 }
133
getSchemaType(const std::string & schema_type,std::optional<std::vector<uint8_t>> * get_schema_type_result_proto)134 ScopedAStatus getSchemaType(
135 const std::string& schema_type,
136 std::optional<std::vector<uint8_t>>* get_schema_type_result_proto) {
137 CHECK_ICING_INIT(icing_);
138
139 GetSchemaTypeResultProto schema_type_result =
140 icing_->GetSchemaType(schema_type);
141 SERIALIZE_AND_RETURN_ASTATUS(schema_type_result,
142 get_schema_type_result_proto);
143 }
144
put(const std::vector<uint8_t> & document_proto,std::optional<std::vector<uint8_t>> * put_result_proto)145 ScopedAStatus put(const std::vector<uint8_t>& document_proto,
146 std::optional<std::vector<uint8_t>>* put_result_proto) {
147 CHECK_ICING_INIT(icing_);
148
149 DocumentProto document;
150 DESERIALIZE_OR_RETURN(document_proto, document);
151 PutResultProto put_result = icing_->Put(document);
152 *put_result_proto = std::vector<uint8_t>();
153 SERIALIZE_AND_RETURN_ASTATUS(put_result, put_result_proto);
154 }
155
batchPut(const std::vector<uint8_t> & put_document_request_proto,std::optional<std::vector<uint8_t>> * batch_put_result_proto)156 ScopedAStatus batchPut(const std::vector<uint8_t>& put_document_request_proto,
157 std::optional<std::vector<uint8_t>>* batch_put_result_proto) {
158 CHECK_ICING_INIT(icing_);
159
160 PutDocumentRequest request;
161 DESERIALIZE_OR_RETURN(put_document_request_proto, request);
162
163 BatchPutResultProto result = icing_->BatchPut(std::move(request));
164
165 *batch_put_result_proto = std::vector<uint8_t>();
166 SERIALIZE_AND_RETURN_ASTATUS(result, batch_put_result_proto);
167 }
168
get(const std::string & name_space,const std::string & uri,const std::vector<uint8_t> & get_result_spec_proto,std::optional<std::vector<uint8_t>> * get_result_proto)169 ScopedAStatus get(const std::string& name_space, const std::string& uri,
170 const std::vector<uint8_t>& get_result_spec_proto,
171 std::optional<std::vector<uint8_t>>* get_result_proto) {
172 CHECK_ICING_INIT(icing_);
173
174 GetResultSpecProto get_result_spec;
175 DESERIALIZE_OR_RETURN(get_result_spec_proto, get_result_spec);
176
177 GetResultProto get_result = icing_->Get(name_space, uri, get_result_spec);
178 SERIALIZE_AND_RETURN_ASTATUS(get_result, get_result_proto);
179 }
180
reportUsage(const std::vector<uint8_t> & usage_report_proto,std::optional<std::vector<uint8_t>> * report_usage_result_proto)181 ScopedAStatus reportUsage(
182 const std::vector<uint8_t>& usage_report_proto,
183 std::optional<std::vector<uint8_t>>* report_usage_result_proto) {
184 CHECK_ICING_INIT(icing_);
185
186 UsageReport usage_report;
187 DESERIALIZE_OR_RETURN(usage_report_proto, usage_report);
188
189 ReportUsageResultProto report_usage_result =
190 icing_->ReportUsage(usage_report);
191 SERIALIZE_AND_RETURN_ASTATUS(report_usage_result,
192 report_usage_result_proto);
193 }
194
getAllNamespaces(std::optional<std::vector<uint8_t>> * get_all_namespaces_result_proto)195 ScopedAStatus getAllNamespaces(
196 std::optional<std::vector<uint8_t>>* get_all_namespaces_result_proto) {
197 CHECK_ICING_INIT(icing_);
198
199 GetAllNamespacesResultProto get_all_namespaces_result =
200 icing_->GetAllNamespaces();
201 SERIALIZE_AND_RETURN_ASTATUS(get_all_namespaces_result,
202 get_all_namespaces_result_proto);
203 }
204
search(const std::vector<uint8_t> & search_spec_proto,const std::vector<uint8_t> & scoring_spec_proto,const std::vector<uint8_t> & result_spec_proto,std::optional<std::vector<uint8_t>> * search_result_proto)205 ScopedAStatus search(
206 const std::vector<uint8_t>& search_spec_proto,
207 const std::vector<uint8_t>& scoring_spec_proto,
208 const std::vector<uint8_t>& result_spec_proto,
209 std::optional<std::vector<uint8_t>>* search_result_proto) {
210 CHECK_ICING_INIT(icing_);
211
212 SearchSpecProto search_spec;
213 DESERIALIZE_OR_RETURN(search_spec_proto, search_spec);
214 ScoringSpecProto scoring_spec;
215 DESERIALIZE_OR_RETURN(scoring_spec_proto, scoring_spec);
216 ResultSpecProto result_spec;
217 DESERIALIZE_OR_RETURN(result_spec_proto, result_spec);
218
219 SearchResultProto search_result =
220 icing_->Search(search_spec, scoring_spec, result_spec);
221 SERIALIZE_AND_RETURN_ASTATUS(search_result, search_result_proto);
222
223 return ScopedAStatus::ok();
224 }
225
getNextPage(int64_t next_page_token,std::optional<std::vector<uint8_t>> * get_next_page_result_proto)226 ScopedAStatus getNextPage(
227 int64_t next_page_token,
228 std::optional<std::vector<uint8_t>>* get_next_page_result_proto) {
229 CHECK_ICING_INIT(icing_);
230
231 SearchResultProto get_next_page_result =
232 icing_->GetNextPage(next_page_token);
233 SERIALIZE_AND_RETURN_ASTATUS(get_next_page_result,
234 get_next_page_result_proto);
235 }
236
invalidateNextPageToken(int64_t next_page_token)237 ScopedAStatus invalidateNextPageToken(int64_t next_page_token) {
238 CHECK_ICING_INIT(icing_);
239
240 icing_->InvalidateNextPageToken(next_page_token);
241 return ScopedAStatus::ok();
242 }
243
openWriteBlob(const std::vector<uint8_t> & blob_handle_proto,std::optional<std::vector<uint8_t>> * blob_proto)244 ScopedAStatus openWriteBlob(const std::vector<uint8_t>& blob_handle_proto,
245 std::optional<std::vector<uint8_t>>* blob_proto) {
246 CHECK_ICING_INIT(icing_);
247
248 BlobHandleProto blob_handle;
249 DESERIALIZE_OR_RETURN(blob_handle_proto, blob_handle);
250
251 BlobProto open_write_blob_result = icing_->OpenWriteBlob(blob_handle);
252 SERIALIZE_AND_RETURN_ASTATUS(open_write_blob_result, blob_proto);
253 }
254
removeBlob(const std::vector<uint8_t> & blob_handle_proto,std::optional<std::vector<uint8_t>> * blob_proto)255 ScopedAStatus removeBlob(const std::vector<uint8_t>& blob_handle_proto,
256 std::optional<std::vector<uint8_t>>* blob_proto) {
257 CHECK_ICING_INIT(icing_);
258
259 BlobHandleProto blob_handle;
260 DESERIALIZE_OR_RETURN(blob_handle_proto, blob_handle);
261
262 BlobProto remove_blob_result = icing_->RemoveBlob(blob_handle);
263 SERIALIZE_AND_RETURN_ASTATUS(remove_blob_result, blob_proto);
264 }
265
openReadBlob(const std::vector<uint8_t> & blob_handle_proto,std::optional<std::vector<uint8_t>> * blob_proto)266 ScopedAStatus openReadBlob(const std::vector<uint8_t>& blob_handle_proto,
267 std::optional<std::vector<uint8_t>>* blob_proto) {
268 CHECK_ICING_INIT(icing_);
269
270 BlobHandleProto blob_handle;
271 DESERIALIZE_OR_RETURN(blob_handle_proto, blob_handle);
272
273 BlobProto open_read_blob_result = icing_->OpenReadBlob(blob_handle);
274 SERIALIZE_AND_RETURN_ASTATUS(open_read_blob_result, blob_proto);
275 }
276
commitBlob(const std::vector<uint8_t> & blob_handle_proto,std::optional<std::vector<uint8_t>> * blob_proto)277 ScopedAStatus commitBlob(const std::vector<uint8_t>& blob_handle_proto,
278 std::optional<std::vector<uint8_t>>* blob_proto) {
279 CHECK_ICING_INIT(icing_);
280
281 BlobHandleProto blob_handle;
282 DESERIALIZE_OR_RETURN(blob_handle_proto, blob_handle);
283
284 BlobProto commit_blob_result = icing_->CommitBlob(blob_handle);
285 SERIALIZE_AND_RETURN_ASTATUS(commit_blob_result, blob_proto);
286 }
287
deleteDoc(const std::string & name_space,const std::string & uri,std::optional<std::vector<uint8_t>> * delete_result_proto)288 ScopedAStatus deleteDoc(
289 const std::string& name_space, const std::string& uri,
290 std::optional<std::vector<uint8_t>>* delete_result_proto) {
291 CHECK_ICING_INIT(icing_);
292
293 DeleteResultProto delete_result = icing_->Delete(name_space, uri);
294 SERIALIZE_AND_RETURN_ASTATUS(delete_result, delete_result_proto);
295 }
296
searchSuggestions(const std::vector<uint8_t> & suggestion_spec_proto,std::optional<std::vector<uint8_t>> * suggestion_response_proto)297 ScopedAStatus searchSuggestions(
298 const std::vector<uint8_t>& suggestion_spec_proto,
299 std::optional<std::vector<uint8_t>>* suggestion_response_proto) {
300 CHECK_ICING_INIT(icing_);
301
302 SuggestionSpecProto suggestion_spec;
303 DESERIALIZE_OR_RETURN(suggestion_spec_proto, suggestion_spec);
304
305 SuggestionResponse suggestion_response =
306 icing_->SearchSuggestions(suggestion_spec);
307 SERIALIZE_AND_RETURN_ASTATUS(suggestion_response,
308 suggestion_response_proto);
309 }
310
deleteByNamespace(const std::string & name_space,std::optional<std::vector<uint8_t>> * delete_by_namespace_result_proto)311 ScopedAStatus deleteByNamespace(
312 const std::string& name_space,
313 std::optional<std::vector<uint8_t>>* delete_by_namespace_result_proto) {
314 CHECK_ICING_INIT(icing_);
315
316 DeleteByNamespaceResultProto delete_by_namespace_result =
317 icing_->DeleteByNamespace(name_space);
318 SERIALIZE_AND_RETURN_ASTATUS(delete_by_namespace_result,
319 delete_by_namespace_result_proto);
320 }
321
deleteBySchemaType(const std::string & schema_type,std::optional<std::vector<uint8_t>> * delete_by_schema_type_result_proto)322 ScopedAStatus deleteBySchemaType(
323 const std::string& schema_type,
324 std::optional<std::vector<uint8_t>>* delete_by_schema_type_result_proto) {
325 CHECK_ICING_INIT(icing_);
326
327 DeleteBySchemaTypeResultProto delete_by_schema_type_result =
328 icing_->DeleteBySchemaType(schema_type);
329 SERIALIZE_AND_RETURN_ASTATUS(delete_by_schema_type_result,
330 delete_by_schema_type_result_proto);
331 }
332
deleteByQuery(const std::vector<uint8_t> & search_spec_proto,bool return_deleted_document_info,std::optional<std::vector<uint8_t>> * delete_by_query_result_proto)333 ScopedAStatus deleteByQuery(
334 const std::vector<uint8_t>& search_spec_proto,
335 bool return_deleted_document_info,
336 std::optional<std::vector<uint8_t>>* delete_by_query_result_proto) {
337 CHECK_ICING_INIT(icing_);
338
339 SearchSpecProto search_spec;
340 DESERIALIZE_OR_RETURN(search_spec_proto, search_spec);
341
342 DeleteByQueryResultProto delete_by_query_result =
343 icing_->DeleteByQuery(search_spec, return_deleted_document_info);
344 SERIALIZE_AND_RETURN_ASTATUS(delete_by_query_result,
345 delete_by_query_result_proto);
346 }
347
persistToDisk(int32_t persist_type_code,std::optional<std::vector<uint8_t>> * persist_to_disk_result_proto)348 ScopedAStatus persistToDisk(
349 int32_t persist_type_code,
350 std::optional<std::vector<uint8_t>>* persist_to_disk_result_proto) {
351 CHECK_ICING_INIT(icing_);
352
353 PersistToDiskResultProto persist_to_disk_result =
354 icing_->PersistToDisk(PersistType::Code(persist_type_code));
355 SERIALIZE_AND_RETURN_ASTATUS(persist_to_disk_result,
356 persist_to_disk_result_proto);
357 }
358
optimize(std::optional<std::vector<uint8_t>> * optimize_result_proto)359 ScopedAStatus optimize(
360 std::optional<std::vector<uint8_t>>* optimize_result_proto) {
361 CHECK_ICING_INIT(icing_);
362
363 OptimizeResultProto optimize_result = icing_->Optimize();
364 SERIALIZE_AND_RETURN_ASTATUS(optimize_result, optimize_result_proto);
365 }
366
getOptimizeInfo(std::optional<std::vector<uint8_t>> * get_optimize_info_result_proto)367 ScopedAStatus getOptimizeInfo(
368 std::optional<std::vector<uint8_t>>* get_optimize_info_result_proto) {
369 CHECK_ICING_INIT(icing_);
370
371 GetOptimizeInfoResultProto get_optimize_info_result =
372 icing_->GetOptimizeInfo();
373 SERIALIZE_AND_RETURN_ASTATUS(get_optimize_info_result,
374 get_optimize_info_result_proto);
375 }
376
getStorageInfo(std::optional<std::vector<uint8_t>> * get_storage_info_result_proto)377 ScopedAStatus getStorageInfo(
378 std::optional<std::vector<uint8_t>>* get_storage_info_result_proto) {
379 CHECK_ICING_INIT(icing_);
380
381 StorageInfoResultProto get_storage_info_result = icing_->GetStorageInfo();
382 SERIALIZE_AND_RETURN_ASTATUS(get_storage_info_result,
383 get_storage_info_result_proto);
384 }
385
getDebugInfo(int32_t verbosity,std::optional<std::vector<uint8_t>> * get_debug_info_result_proto)386 ScopedAStatus getDebugInfo(
387 int32_t verbosity,
388 std::optional<std::vector<uint8_t>>* get_debug_info_result_proto) {
389 CHECK_ICING_INIT(icing_);
390
391 DebugInfoResultProto get_debug_info_result =
392 icing_->GetDebugInfo(DebugInfoVerbosity::Code(verbosity));
393 SERIALIZE_AND_RETURN_ASTATUS(get_debug_info_result,
394 get_debug_info_result_proto);
395 }
396
397 protected:
398 std::unique_ptr<icing::lib::IcingSearchEngine> icing_ = nullptr;
399 uint32_t uid_;
400 };
401
402 class IsolatedStorageServiceImpl : public BnIsolatedStorageService {
403 public:
404 IsolatedStorageServiceImpl() = default;
405
406 private:
quit()407 ScopedAStatus quit() override {
408 ICING_LOG(INFO) << "Received quit request, exiting";
409 for (const auto& [unused, connection] : icing_connections_) {
410 connection->close();
411 }
412 exit(0);
413 }
414
getOrCreateIcingConnection(int32_t uid,std::shared_ptr<aidl::com::android::isolated_storage_service::IIcingSearchEngine> * icing_server)415 ScopedAStatus getOrCreateIcingConnection(
416 int32_t uid,
417 std::shared_ptr<
418 aidl::com::android::isolated_storage_service::IIcingSearchEngine>*
419 icing_server) override {
420 auto connection = icing_connections_.find(uid);
421 if (connection != icing_connections_.end()) {
422 *icing_server = connection->second;
423 return ScopedAStatus::ok();
424 }
425 icing_connections_[uid] =
426 ndk::SharedRefBase::make<IcingConnectionImpl>(uid);
427 *icing_server = icing_connections_[uid];
428 return ScopedAStatus::ok();
429 }
430
431 std::map<int32_t, std::shared_ptr<IcingConnectionImpl>> icing_connections_;
432 };
433 } // namespace
434
AVmPayload_main()435 extern "C" int AVmPayload_main() {
436 ICING_LOG(INFO) << "IsolatedStorageService VM Payload starting";
437 auto service = ndk::SharedRefBase::make<IsolatedStorageServiceImpl>();
438 auto callback = []([[maybe_unused]] void* param) {
439 ICING_LOG(INFO) << "IsolatedStorageService VM Payload ready";
440 AVmPayload_notifyPayloadReady();
441 };
442 AVmPayload_runVsockRpcServer(service->asBinder().get(), service->PORT,
443 callback, /*param=*/nullptr);
444 }
445