1 /* 2 * Copyright (C) 2023 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 package android.health.connect.aidl; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.health.connect.HealthConnectManager; 22 import android.health.connect.internal.ParcelUtils; 23 import android.health.connect.internal.datatypes.RecordInternal; 24 import android.health.connect.internal.datatypes.utils.ParcelRecordConverter; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import java.lang.reflect.InvocationTargetException; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * A wrapper to carry a list of entries of type {@link RecordInternal} from and to {@link 34 * HealthConnectManager} 35 * 36 * @hide 37 */ 38 public class RecordsParcel implements Parcelable { 39 @NonNull 40 public static final Creator<RecordsParcel> CREATOR = 41 new Creator<>() { 42 @Override 43 public RecordsParcel createFromParcel(Parcel in) { 44 return new RecordsParcel(in); 45 } 46 47 @Override 48 public RecordsParcel[] newArray(int size) { 49 return new RecordsParcel[size]; 50 } 51 }; 52 53 private final List<RecordInternal<?>> mRecordInternals; 54 private long mRecordsChunkSize; 55 private List<Long> mRecordsSize; 56 RecordsParcel(@onNull List<RecordInternal<?>> recordInternals)57 public RecordsParcel(@NonNull List<RecordInternal<?>> recordInternals) { 58 mRecordInternals = recordInternals; 59 } 60 RecordsParcel(@onNull Parcel in)61 private RecordsParcel(@NonNull Parcel in) { 62 in = ParcelUtils.getParcelForSharedMemoryIfRequired(in); 63 int size = in.readInt(); 64 mRecordInternals = new ArrayList<>(size); 65 mRecordsSize = new ArrayList<>(size); 66 long remainingParcelSize = in.dataAvail(); 67 mRecordsChunkSize = remainingParcelSize; 68 for (int i = 0; i < size; i++) { 69 int identifier = in.readInt(); 70 try { 71 mRecordInternals.add(ParcelRecordConverter.getInstance().getRecord(in, identifier)); 72 // Calculating record size based on before and after values of parcel size. 73 mRecordsSize.add(remainingParcelSize - in.dataAvail()); 74 remainingParcelSize = in.dataAvail(); 75 } catch (InstantiationException 76 | IllegalAccessException 77 | NoSuchMethodException 78 | InvocationTargetException e) { 79 throw new IllegalArgumentException(); 80 } 81 } 82 } 83 84 @Override describeContents()85 public int describeContents() { 86 return 0; 87 } 88 89 @Override writeToParcel(@onNull Parcel dest, int flags)90 public void writeToParcel(@NonNull Parcel dest, int flags) { 91 ParcelUtils.putToRequiredMemory(dest, flags, this::writeToParcelInternal); 92 } 93 94 @NonNull getRecords()95 public List<RecordInternal<?>> getRecords() { 96 return mRecordInternals; 97 } 98 99 /** 100 * @return a list containing size of the individual records. Used for memory rate limiting. 101 */ 102 @Nullable getRecordsSize()103 public List<Long> getRecordsSize() { 104 return mRecordsSize; 105 } 106 107 /** 108 * @return size of the record parcel. Used for memory rate limiting. 109 */ getRecordsChunkSize()110 public long getRecordsChunkSize() { 111 return mRecordsChunkSize; 112 } 113 writeToParcelInternal(@onNull Parcel dest)114 private void writeToParcelInternal(@NonNull Parcel dest) { 115 dest.writeInt(mRecordInternals.size()); 116 for (RecordInternal<?> recordInternal : mRecordInternals) { 117 dest.writeInt(recordInternal.getRecordType()); 118 recordInternal.writeToParcel(dest); 119 } 120 } 121 } 122