1 /* 2 * Copyright (C) 2019 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.service.dataloader; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SystemApi; 23 import android.app.Service; 24 import android.content.Intent; 25 import android.content.pm.DataLoaderParams; 26 import android.content.pm.DataLoaderParamsParcel; 27 import android.content.pm.FileSystemControlParcel; 28 import android.content.pm.IDataLoader; 29 import android.content.pm.IDataLoaderStatusListener; 30 import android.content.pm.InstallationFile; 31 import android.content.pm.InstallationFileParcel; 32 import android.os.IBinder; 33 import android.os.ParcelFileDescriptor; 34 import android.util.ExceptionUtils; 35 import android.util.Slog; 36 37 import libcore.io.IoUtils; 38 39 import java.io.IOException; 40 import java.util.Collection; 41 42 /** 43 * The base class for implementing data loader service to control data loaders. Expecting 44 * Incremental Service to bind to a children class of this. 45 * 46 * WARNING: This is a system API to aid internal development. 47 * Use at your own risk. It will change or be removed without warning. 48 * 49 * TODO(b/136132412): update with latest API design 50 * 51 * @hide 52 */ 53 @SystemApi 54 public abstract class DataLoaderService extends Service { 55 private static final String TAG = "DataLoaderService"; 56 private final DataLoaderBinderService mBinder = new DataLoaderBinderService(); 57 58 /** 59 * Managed DataLoader interface. Each instance corresponds to a single installation session. 60 * @hide 61 */ 62 @SystemApi 63 public interface DataLoader { 64 /** 65 * A virtual constructor. 66 * 67 * @param dataLoaderParams parameters set in the installation session 68 * @param connector FS API wrapper 69 * @return True if initialization of a Data Loader was successful. False will be reported to 70 * PackageManager and fail the installation 71 */ onCreate(@onNull DataLoaderParams dataLoaderParams, @NonNull FileSystemConnector connector)72 boolean onCreate(@NonNull DataLoaderParams dataLoaderParams, 73 @NonNull FileSystemConnector connector); 74 75 /** 76 * Prepare installation image. After this method succeeds installer will validate the files 77 * and continue installation. 78 * 79 * @param addedFiles list of files created in this installation session. 80 * @param removedFiles list of files removed in this installation session. 81 * @return false if unable to create and populate all addedFiles. 82 */ onPrepareImage(@onNull Collection<InstallationFile> addedFiles, @NonNull Collection<String> removedFiles)83 boolean onPrepareImage(@NonNull Collection<InstallationFile> addedFiles, 84 @NonNull Collection<String> removedFiles); 85 } 86 87 /** 88 * DataLoader factory method. 89 * 90 * @return An instance of a DataLoader. 91 * @hide 92 */ 93 @SystemApi onCreateDataLoader(@onNull DataLoaderParams dataLoaderParams)94 public @Nullable DataLoader onCreateDataLoader(@NonNull DataLoaderParams dataLoaderParams) { 95 return null; 96 } 97 98 /** 99 * @hide 100 */ onBind(@onNull Intent intent)101 public final @NonNull IBinder onBind(@NonNull Intent intent) { 102 return (IBinder) mBinder; 103 } 104 105 private class DataLoaderBinderService extends IDataLoader.Stub { 106 @Override create(int id, @NonNull DataLoaderParamsParcel params, @NonNull FileSystemControlParcel control, @NonNull IDataLoaderStatusListener listener)107 public void create(int id, @NonNull DataLoaderParamsParcel params, 108 @NonNull FileSystemControlParcel control, 109 @NonNull IDataLoaderStatusListener listener) 110 throws RuntimeException { 111 try { 112 nativeCreateDataLoader(id, control, params, listener); 113 } catch (Exception ex) { 114 Slog.e(TAG, "Failed to create native loader for " + id, ex); 115 destroy(id); 116 throw new RuntimeException(ex); 117 } finally { 118 if (control.incremental != null) { 119 IoUtils.closeQuietly(control.incremental.cmd); 120 IoUtils.closeQuietly(control.incremental.pendingReads); 121 IoUtils.closeQuietly(control.incremental.log); 122 } 123 } 124 } 125 126 @Override start(int id)127 public void start(int id) { 128 if (!nativeStartDataLoader(id)) { 129 Slog.e(TAG, "Failed to start loader: " + id); 130 } 131 } 132 133 @Override stop(int id)134 public void stop(int id) { 135 if (!nativeStopDataLoader(id)) { 136 Slog.w(TAG, "Failed to stop loader: " + id); 137 } 138 } 139 140 @Override destroy(int id)141 public void destroy(int id) { 142 if (!nativeDestroyDataLoader(id)) { 143 Slog.w(TAG, "Failed to destroy loader: " + id); 144 } 145 } 146 147 @Override prepareImage(int id, InstallationFileParcel[] addedFiles, String[] removedFiles)148 public void prepareImage(int id, InstallationFileParcel[] addedFiles, 149 String[] removedFiles) { 150 if (!nativePrepareImage(id, addedFiles, removedFiles)) { 151 Slog.w(TAG, "Failed to prepare image for data loader: " + id); 152 } 153 } 154 } 155 156 /** 157 * Used by the DataLoaderService implementations. 158 * 159 * @hide 160 */ 161 @SystemApi 162 public static final class FileSystemConnector { 163 /** 164 * Create a wrapper for a native instance. 165 * 166 * @hide 167 */ FileSystemConnector(long nativeInstance)168 FileSystemConnector(long nativeInstance) { 169 mNativeInstance = nativeInstance; 170 } 171 172 /** 173 * Write data to an installation file from an arbitrary FD. 174 * 175 * @param name name of file previously added to the installation session. 176 * @param offsetBytes offset into the file to begin writing at, or 0 to start at the 177 * beginning of the file. 178 * @param lengthBytes total size of the file being written, used to preallocate the 179 * underlying disk space, or -1 if unknown. The system may clear various 180 * caches as needed to allocate this space. 181 * @param incomingFd FD to read bytes from. 182 * @throws IOException if trouble opening the file for writing, such as lack of disk space 183 * or unavailable media. 184 */ 185 @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) writeData(@onNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor incomingFd)186 public void writeData(@NonNull String name, long offsetBytes, long lengthBytes, 187 @NonNull ParcelFileDescriptor incomingFd) throws IOException { 188 try { 189 nativeWriteData(mNativeInstance, name, offsetBytes, lengthBytes, incomingFd); 190 } catch (RuntimeException e) { 191 ExceptionUtils.maybeUnwrapIOException(e); 192 throw e; 193 } 194 } 195 196 private final long mNativeInstance; 197 } 198 199 /* Native methods */ nativeCreateDataLoader(int storageId, @NonNull FileSystemControlParcel control, @NonNull DataLoaderParamsParcel params, IDataLoaderStatusListener listener)200 private native boolean nativeCreateDataLoader(int storageId, 201 @NonNull FileSystemControlParcel control, 202 @NonNull DataLoaderParamsParcel params, 203 IDataLoaderStatusListener listener); 204 nativeStartDataLoader(int storageId)205 private native boolean nativeStartDataLoader(int storageId); 206 nativeStopDataLoader(int storageId)207 private native boolean nativeStopDataLoader(int storageId); 208 nativeDestroyDataLoader(int storageId)209 private native boolean nativeDestroyDataLoader(int storageId); 210 nativePrepareImage(int storageId, InstallationFileParcel[] addedFiles, String[] removedFiles)211 private native boolean nativePrepareImage(int storageId, 212 InstallationFileParcel[] addedFiles, String[] removedFiles); 213 nativeWriteData(long nativeInstance, String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd)214 private static native void nativeWriteData(long nativeInstance, String name, long offsetBytes, 215 long lengthBytes, ParcelFileDescriptor incomingFd); 216 217 } 218