1 // Copyright (C) 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.android.icing; 16 17 import android.util.Log; 18 import androidx.annotation.NonNull; 19 import androidx.annotation.Nullable; 20 import com.google.android.icing.proto.DebugInfoResultProto; 21 import com.google.android.icing.proto.DeleteByNamespaceResultProto; 22 import com.google.android.icing.proto.DeleteByQueryResultProto; 23 import com.google.android.icing.proto.DeleteBySchemaTypeResultProto; 24 import com.google.android.icing.proto.DeleteResultProto; 25 import com.google.android.icing.proto.GetAllNamespacesResultProto; 26 import com.google.android.icing.proto.GetOptimizeInfoResultProto; 27 import com.google.android.icing.proto.GetResultProto; 28 import com.google.android.icing.proto.GetSchemaResultProto; 29 import com.google.android.icing.proto.GetSchemaTypeResultProto; 30 import com.google.android.icing.proto.InitializeResultProto; 31 import com.google.android.icing.proto.OptimizeResultProto; 32 import com.google.android.icing.proto.PersistToDiskResultProto; 33 import com.google.android.icing.proto.PutResultProto; 34 import com.google.android.icing.proto.ReportUsageResultProto; 35 import com.google.android.icing.proto.ResetResultProto; 36 import com.google.android.icing.proto.SearchResultProto; 37 import com.google.android.icing.proto.SetSchemaResultProto; 38 import com.google.android.icing.proto.StatusProto; 39 import com.google.android.icing.proto.StorageInfoResultProto; 40 import com.google.android.icing.proto.SuggestionResponse; 41 import com.google.protobuf.ExtensionRegistryLite; 42 import com.google.protobuf.InvalidProtocolBufferException; 43 44 /** 45 * Contains utility methods for IcingSearchEngine to convert byte arrays to the corresponding 46 * protos. 47 * 48 * <p>It is also being used by AppSearch dynamite 0p client APIs to convert byte arrays to the 49 * protos. 50 */ 51 public final class IcingSearchEngineUtils { 52 private static final String TAG = "IcingSearchEngineUtils"; 53 private static final ExtensionRegistryLite EXTENSION_REGISTRY_LITE = 54 ExtensionRegistryLite.getEmptyRegistry(); 55 IcingSearchEngineUtils()56 private IcingSearchEngineUtils() {} 57 58 // TODO(b/240333360) Check to see if we can use one template function to replace those 59 @NonNull byteArrayToInitializeResultProto( @ullable byte[] initializeResultBytes)60 public static InitializeResultProto byteArrayToInitializeResultProto( 61 @Nullable byte[] initializeResultBytes) { 62 if (initializeResultBytes == null) { 63 Log.e(TAG, "Received null InitializeResult from native."); 64 return InitializeResultProto.newBuilder() 65 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 66 .build(); 67 } 68 69 try { 70 return InitializeResultProto.parseFrom(initializeResultBytes, EXTENSION_REGISTRY_LITE); 71 } catch (InvalidProtocolBufferException e) { 72 Log.e(TAG, "Error parsing InitializeResultProto.", e); 73 return InitializeResultProto.newBuilder() 74 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 75 .build(); 76 } 77 } 78 79 @NonNull byteArrayToSetSchemaResultProto( @ullable byte[] setSchemaResultBytes)80 public static SetSchemaResultProto byteArrayToSetSchemaResultProto( 81 @Nullable byte[] setSchemaResultBytes) { 82 if (setSchemaResultBytes == null) { 83 Log.e(TAG, "Received null SetSchemaResultProto from native."); 84 return SetSchemaResultProto.newBuilder() 85 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 86 .build(); 87 } 88 89 try { 90 return SetSchemaResultProto.parseFrom(setSchemaResultBytes, EXTENSION_REGISTRY_LITE); 91 } catch (InvalidProtocolBufferException e) { 92 Log.e(TAG, "Error parsing SetSchemaResultProto.", e); 93 return SetSchemaResultProto.newBuilder() 94 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 95 .build(); 96 } 97 } 98 99 @NonNull byteArrayToGetSchemaResultProto( @ullable byte[] getSchemaResultBytes)100 public static GetSchemaResultProto byteArrayToGetSchemaResultProto( 101 @Nullable byte[] getSchemaResultBytes) { 102 if (getSchemaResultBytes == null) { 103 Log.e(TAG, "Received null GetSchemaResultProto from native."); 104 return GetSchemaResultProto.newBuilder() 105 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 106 .build(); 107 } 108 109 try { 110 return GetSchemaResultProto.parseFrom(getSchemaResultBytes, EXTENSION_REGISTRY_LITE); 111 } catch (InvalidProtocolBufferException e) { 112 Log.e(TAG, "Error parsing GetSchemaResultProto.", e); 113 return GetSchemaResultProto.newBuilder() 114 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 115 .build(); 116 } 117 } 118 119 @NonNull byteArrayToGetSchemaTypeResultProto( @ullable byte[] getSchemaTypeResultBytes)120 public static GetSchemaTypeResultProto byteArrayToGetSchemaTypeResultProto( 121 @Nullable byte[] getSchemaTypeResultBytes) { 122 if (getSchemaTypeResultBytes == null) { 123 Log.e(TAG, "Received null GetSchemaTypeResultProto from native."); 124 return GetSchemaTypeResultProto.newBuilder() 125 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 126 .build(); 127 } 128 129 try { 130 return GetSchemaTypeResultProto.parseFrom(getSchemaTypeResultBytes, EXTENSION_REGISTRY_LITE); 131 } catch (InvalidProtocolBufferException e) { 132 Log.e(TAG, "Error parsing GetSchemaTypeResultProto.", e); 133 return GetSchemaTypeResultProto.newBuilder() 134 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 135 .build(); 136 } 137 } 138 139 @NonNull byteArrayToPutResultProto(@ullable byte[] putResultBytes)140 public static PutResultProto byteArrayToPutResultProto(@Nullable byte[] putResultBytes) { 141 if (putResultBytes == null) { 142 Log.e(TAG, "Received null PutResultProto from native."); 143 return PutResultProto.newBuilder() 144 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 145 .build(); 146 } 147 148 try { 149 return PutResultProto.parseFrom(putResultBytes, EXTENSION_REGISTRY_LITE); 150 } catch (InvalidProtocolBufferException e) { 151 Log.e(TAG, "Error parsing PutResultProto.", e); 152 return PutResultProto.newBuilder() 153 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 154 .build(); 155 } 156 } 157 158 @NonNull byteArrayToGetResultProto(@ullable byte[] getResultBytes)159 public static GetResultProto byteArrayToGetResultProto(@Nullable byte[] getResultBytes) { 160 if (getResultBytes == null) { 161 Log.e(TAG, "Received null GetResultProto from native."); 162 return GetResultProto.newBuilder() 163 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 164 .build(); 165 } 166 167 try { 168 return GetResultProto.parseFrom(getResultBytes, EXTENSION_REGISTRY_LITE); 169 } catch (InvalidProtocolBufferException e) { 170 Log.e(TAG, "Error parsing GetResultProto.", e); 171 return GetResultProto.newBuilder() 172 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 173 .build(); 174 } 175 } 176 177 @NonNull byteArrayToReportUsageResultProto( @ullable byte[] reportUsageResultBytes)178 public static ReportUsageResultProto byteArrayToReportUsageResultProto( 179 @Nullable byte[] reportUsageResultBytes) { 180 if (reportUsageResultBytes == null) { 181 Log.e(TAG, "Received null ReportUsageResultProto from native."); 182 return ReportUsageResultProto.newBuilder() 183 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 184 .build(); 185 } 186 187 try { 188 return ReportUsageResultProto.parseFrom(reportUsageResultBytes, EXTENSION_REGISTRY_LITE); 189 } catch (InvalidProtocolBufferException e) { 190 Log.e(TAG, "Error parsing ReportUsageResultProto.", e); 191 return ReportUsageResultProto.newBuilder() 192 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 193 .build(); 194 } 195 } 196 197 @NonNull byteArrayToGetAllNamespacesResultProto( @ullable byte[] getAllNamespacesResultBytes)198 public static GetAllNamespacesResultProto byteArrayToGetAllNamespacesResultProto( 199 @Nullable byte[] getAllNamespacesResultBytes) { 200 if (getAllNamespacesResultBytes == null) { 201 Log.e(TAG, "Received null GetAllNamespacesResultProto from native."); 202 return GetAllNamespacesResultProto.newBuilder() 203 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 204 .build(); 205 } 206 207 try { 208 return GetAllNamespacesResultProto.parseFrom( 209 getAllNamespacesResultBytes, EXTENSION_REGISTRY_LITE); 210 } catch (InvalidProtocolBufferException e) { 211 Log.e(TAG, "Error parsing GetAllNamespacesResultProto.", e); 212 return GetAllNamespacesResultProto.newBuilder() 213 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 214 .build(); 215 } 216 } 217 218 @NonNull byteArrayToSearchResultProto(@ullable byte[] searchResultBytes)219 public static SearchResultProto byteArrayToSearchResultProto(@Nullable byte[] searchResultBytes) { 220 if (searchResultBytes == null) { 221 Log.e(TAG, "Received null SearchResultProto from native."); 222 return SearchResultProto.newBuilder() 223 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 224 .build(); 225 } 226 227 try { 228 SearchResultProto.Builder searchResultProtoBuilder = 229 SearchResultProto.newBuilder().mergeFrom(searchResultBytes, EXTENSION_REGISTRY_LITE); 230 setNativeToJavaJniLatency(searchResultProtoBuilder); 231 return searchResultProtoBuilder.build(); 232 } catch (InvalidProtocolBufferException e) { 233 Log.e(TAG, "Error parsing SearchResultProto.", e); 234 return SearchResultProto.newBuilder() 235 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 236 .build(); 237 } 238 } 239 setNativeToJavaJniLatency( SearchResultProto.Builder searchResultProtoBuilder)240 private static void setNativeToJavaJniLatency( 241 SearchResultProto.Builder searchResultProtoBuilder) { 242 int nativeToJavaLatencyMs = 243 (int) 244 (System.currentTimeMillis() 245 - searchResultProtoBuilder.getQueryStats().getNativeToJavaStartTimestampMs()); 246 searchResultProtoBuilder.setQueryStats( 247 searchResultProtoBuilder.getQueryStats().toBuilder() 248 .setNativeToJavaJniLatencyMs(nativeToJavaLatencyMs)); 249 } 250 251 @NonNull byteArrayToDeleteResultProto(@ullable byte[] deleteResultBytes)252 public static DeleteResultProto byteArrayToDeleteResultProto(@Nullable byte[] deleteResultBytes) { 253 if (deleteResultBytes == null) { 254 Log.e(TAG, "Received null DeleteResultProto from native."); 255 return DeleteResultProto.newBuilder() 256 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 257 .build(); 258 } 259 260 try { 261 return DeleteResultProto.parseFrom(deleteResultBytes, EXTENSION_REGISTRY_LITE); 262 } catch (InvalidProtocolBufferException e) { 263 Log.e(TAG, "Error parsing DeleteResultProto.", e); 264 return DeleteResultProto.newBuilder() 265 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 266 .build(); 267 } 268 } 269 270 @NonNull byteArrayToSuggestionResponse( @ullable byte[] suggestionResponseBytes)271 public static SuggestionResponse byteArrayToSuggestionResponse( 272 @Nullable byte[] suggestionResponseBytes) { 273 if (suggestionResponseBytes == null) { 274 Log.e(TAG, "Received null suggestionResponseBytes from native."); 275 return SuggestionResponse.newBuilder() 276 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 277 .build(); 278 } 279 280 try { 281 return SuggestionResponse.parseFrom(suggestionResponseBytes, EXTENSION_REGISTRY_LITE); 282 } catch (InvalidProtocolBufferException e) { 283 Log.e(TAG, "Error parsing suggestionResponseBytes.", e); 284 return SuggestionResponse.newBuilder() 285 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 286 .build(); 287 } 288 } 289 290 @NonNull byteArrayToDeleteByNamespaceResultProto( @ullable byte[] deleteByNamespaceResultBytes)291 public static DeleteByNamespaceResultProto byteArrayToDeleteByNamespaceResultProto( 292 @Nullable byte[] deleteByNamespaceResultBytes) { 293 if (deleteByNamespaceResultBytes == null) { 294 Log.e(TAG, "Received null DeleteByNamespaceResultProto from native."); 295 return DeleteByNamespaceResultProto.newBuilder() 296 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 297 .build(); 298 } 299 300 try { 301 return DeleteByNamespaceResultProto.parseFrom( 302 deleteByNamespaceResultBytes, EXTENSION_REGISTRY_LITE); 303 } catch (InvalidProtocolBufferException e) { 304 Log.e(TAG, "Error parsing DeleteByNamespaceResultProto.", e); 305 return DeleteByNamespaceResultProto.newBuilder() 306 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 307 .build(); 308 } 309 } 310 311 @NonNull byteArrayToDeleteBySchemaTypeResultProto( @ullable byte[] deleteBySchemaTypeResultBytes)312 public static DeleteBySchemaTypeResultProto byteArrayToDeleteBySchemaTypeResultProto( 313 @Nullable byte[] deleteBySchemaTypeResultBytes) { 314 if (deleteBySchemaTypeResultBytes == null) { 315 Log.e(TAG, "Received null DeleteBySchemaTypeResultProto from native."); 316 return DeleteBySchemaTypeResultProto.newBuilder() 317 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 318 .build(); 319 } 320 321 try { 322 return DeleteBySchemaTypeResultProto.parseFrom( 323 deleteBySchemaTypeResultBytes, EXTENSION_REGISTRY_LITE); 324 } catch (InvalidProtocolBufferException e) { 325 Log.e(TAG, "Error parsing DeleteBySchemaTypeResultProto.", e); 326 return DeleteBySchemaTypeResultProto.newBuilder() 327 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 328 .build(); 329 } 330 } 331 332 @NonNull byteArrayToDeleteByQueryResultProto( @ullable byte[] deleteResultBytes)333 public static DeleteByQueryResultProto byteArrayToDeleteByQueryResultProto( 334 @Nullable byte[] deleteResultBytes) { 335 if (deleteResultBytes == null) { 336 Log.e(TAG, "Received null DeleteResultProto from native."); 337 return DeleteByQueryResultProto.newBuilder() 338 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 339 .build(); 340 } 341 342 try { 343 return DeleteByQueryResultProto.parseFrom(deleteResultBytes, EXTENSION_REGISTRY_LITE); 344 } catch (InvalidProtocolBufferException e) { 345 Log.e(TAG, "Error parsing DeleteResultProto.", e); 346 return DeleteByQueryResultProto.newBuilder() 347 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 348 .build(); 349 } 350 } 351 352 @NonNull byteArrayToPersistToDiskResultProto( @ullable byte[] persistToDiskResultBytes)353 public static PersistToDiskResultProto byteArrayToPersistToDiskResultProto( 354 @Nullable byte[] persistToDiskResultBytes) { 355 if (persistToDiskResultBytes == null) { 356 Log.e(TAG, "Received null PersistToDiskResultProto from native."); 357 return PersistToDiskResultProto.newBuilder() 358 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 359 .build(); 360 } 361 362 try { 363 return PersistToDiskResultProto.parseFrom(persistToDiskResultBytes, EXTENSION_REGISTRY_LITE); 364 } catch (InvalidProtocolBufferException e) { 365 Log.e(TAG, "Error parsing PersistToDiskResultProto.", e); 366 return PersistToDiskResultProto.newBuilder() 367 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 368 .build(); 369 } 370 } 371 372 @NonNull byteArrayToOptimizeResultProto( @ullable byte[] optimizeResultBytes)373 public static OptimizeResultProto byteArrayToOptimizeResultProto( 374 @Nullable byte[] optimizeResultBytes) { 375 if (optimizeResultBytes == null) { 376 Log.e(TAG, "Received null OptimizeResultProto from native."); 377 return OptimizeResultProto.newBuilder() 378 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 379 .build(); 380 } 381 382 try { 383 return OptimizeResultProto.parseFrom(optimizeResultBytes, EXTENSION_REGISTRY_LITE); 384 } catch (InvalidProtocolBufferException e) { 385 Log.e(TAG, "Error parsing OptimizeResultProto.", e); 386 return OptimizeResultProto.newBuilder() 387 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 388 .build(); 389 } 390 } 391 392 @NonNull byteArrayToGetOptimizeInfoResultProto( @ullable byte[] getOptimizeInfoResultBytes)393 public static GetOptimizeInfoResultProto byteArrayToGetOptimizeInfoResultProto( 394 @Nullable byte[] getOptimizeInfoResultBytes) { 395 if (getOptimizeInfoResultBytes == null) { 396 Log.e(TAG, "Received null GetOptimizeInfoResultProto from native."); 397 return GetOptimizeInfoResultProto.newBuilder() 398 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 399 .build(); 400 } 401 402 try { 403 return GetOptimizeInfoResultProto.parseFrom( 404 getOptimizeInfoResultBytes, EXTENSION_REGISTRY_LITE); 405 } catch (InvalidProtocolBufferException e) { 406 Log.e(TAG, "Error parsing GetOptimizeInfoResultProto.", e); 407 return GetOptimizeInfoResultProto.newBuilder() 408 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 409 .build(); 410 } 411 } 412 413 @NonNull byteArrayToStorageInfoResultProto( @ullable byte[] storageInfoResultProtoBytes)414 public static StorageInfoResultProto byteArrayToStorageInfoResultProto( 415 @Nullable byte[] storageInfoResultProtoBytes) { 416 if (storageInfoResultProtoBytes == null) { 417 Log.e(TAG, "Received null StorageInfoResultProto from native."); 418 return StorageInfoResultProto.newBuilder() 419 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 420 .build(); 421 } 422 423 try { 424 return StorageInfoResultProto.parseFrom(storageInfoResultProtoBytes, EXTENSION_REGISTRY_LITE); 425 } catch (InvalidProtocolBufferException e) { 426 Log.e(TAG, "Error parsing GetOptimizeInfoResultProto.", e); 427 return StorageInfoResultProto.newBuilder() 428 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 429 .build(); 430 } 431 } 432 433 @NonNull byteArrayToDebugInfoResultProto( @ullable byte[] debugInfoResultProtoBytes)434 public static DebugInfoResultProto byteArrayToDebugInfoResultProto( 435 @Nullable byte[] debugInfoResultProtoBytes) { 436 if (debugInfoResultProtoBytes == null) { 437 Log.e(TAG, "Received null DebugInfoResultProto from native."); 438 return DebugInfoResultProto.newBuilder() 439 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 440 .build(); 441 } 442 443 try { 444 return DebugInfoResultProto.parseFrom(debugInfoResultProtoBytes, EXTENSION_REGISTRY_LITE); 445 } catch (InvalidProtocolBufferException e) { 446 Log.e(TAG, "Error parsing DebugInfoResultProto.", e); 447 return DebugInfoResultProto.newBuilder() 448 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 449 .build(); 450 } 451 } 452 453 @NonNull byteArrayToResetResultProto(@ullable byte[] resetResultBytes)454 public static ResetResultProto byteArrayToResetResultProto(@Nullable byte[] resetResultBytes) { 455 if (resetResultBytes == null) { 456 Log.e(TAG, "Received null ResetResultProto from native."); 457 return ResetResultProto.newBuilder() 458 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 459 .build(); 460 } 461 462 try { 463 return ResetResultProto.parseFrom(resetResultBytes, EXTENSION_REGISTRY_LITE); 464 } catch (InvalidProtocolBufferException e) { 465 Log.e(TAG, "Error parsing ResetResultProto.", e); 466 return ResetResultProto.newBuilder() 467 .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL)) 468 .build(); 469 } 470 } 471 } 472