Incremental install via adb.
- passing V4 signature to IncFS, - cleanup and use InstallationFile everywhere, - pass params to DataLoader creation, - minor refactor for PackageManagerShellCommandDataLoader to prepare for Incremental data loading. Test: atest PackageManagerShellCommandTest Bug: b/136132412 b/133435829 Change-Id: Iacc3e4c51c0fa3410b076147ce153a1303246189
This commit is contained in:
@@ -2007,18 +2007,15 @@ package android.content.pm {
|
||||
}
|
||||
|
||||
public final class InstallationFile implements android.os.Parcelable {
|
||||
ctor public InstallationFile(@NonNull String, long, @Nullable byte[]);
|
||||
ctor public InstallationFile(int, @NonNull String, long, @Nullable byte[], @Nullable byte[]);
|
||||
method public int describeContents();
|
||||
method public int getFileType();
|
||||
method public long getLengthBytes();
|
||||
method public int getLocation();
|
||||
method @Nullable public byte[] getMetadata();
|
||||
method @NonNull public String getName();
|
||||
method public long getSize();
|
||||
method @Nullable public byte[] getSignature();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstallationFile> CREATOR;
|
||||
field public static final int FILE_TYPE_APK = 0; // 0x0
|
||||
field public static final int FILE_TYPE_LIB = 1; // 0x1
|
||||
field public static final int FILE_TYPE_OBB = 2; // 0x2
|
||||
field public static final int FILE_TYPE_UNKNOWN = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
public final class InstantAppInfo implements android.os.Parcelable {
|
||||
@@ -10317,7 +10314,7 @@ package android.service.dataloader {
|
||||
|
||||
public abstract class DataLoaderService extends android.app.Service {
|
||||
ctor public DataLoaderService();
|
||||
method @Nullable public android.service.dataloader.DataLoaderService.DataLoader onCreateDataLoader();
|
||||
method @Nullable public android.service.dataloader.DataLoaderService.DataLoader onCreateDataLoader(@NonNull android.content.pm.DataLoaderParams);
|
||||
}
|
||||
|
||||
public static interface DataLoaderService.DataLoader {
|
||||
|
||||
@@ -16,82 +16,59 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Defines the properties of a file in an installation session.
|
||||
* TODO(b/136132412): update with new APIs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class InstallationFile implements Parcelable {
|
||||
public static final int FILE_TYPE_UNKNOWN = -1;
|
||||
public static final int FILE_TYPE_APK = 0;
|
||||
public static final int FILE_TYPE_LIB = 1;
|
||||
public static final int FILE_TYPE_OBB = 2;
|
||||
private final @PackageInstaller.FileLocation int mLocation;
|
||||
private final @NonNull String mName;
|
||||
private final long mLengthBytes;
|
||||
private final @Nullable byte[] mMetadata;
|
||||
private final @Nullable byte[] mSignature;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = {"FILE_TYPE_"}, value = {
|
||||
FILE_TYPE_APK,
|
||||
FILE_TYPE_LIB,
|
||||
FILE_TYPE_OBB,
|
||||
})
|
||||
public @interface FileType {
|
||||
}
|
||||
|
||||
private String mFileName;
|
||||
private @FileType int mFileType;
|
||||
private long mFileSize;
|
||||
private byte[] mMetadata;
|
||||
|
||||
public InstallationFile(@NonNull String fileName, long fileSize,
|
||||
@Nullable byte[] metadata) {
|
||||
mFileName = fileName;
|
||||
mFileSize = fileSize;
|
||||
public InstallationFile(@PackageInstaller.FileLocation int location, @NonNull String name,
|
||||
long lengthBytes, @Nullable byte[] metadata, @Nullable byte[] signature) {
|
||||
mLocation = location;
|
||||
mName = name;
|
||||
mLengthBytes = lengthBytes;
|
||||
mMetadata = metadata;
|
||||
if (fileName.toLowerCase().endsWith(".apk")) {
|
||||
mFileType = FILE_TYPE_APK;
|
||||
} else if (fileName.toLowerCase().endsWith(".obb")) {
|
||||
mFileType = FILE_TYPE_OBB;
|
||||
} else if (fileName.toLowerCase().endsWith(".so") && fileName.toLowerCase().startsWith(
|
||||
"lib/")) {
|
||||
mFileType = FILE_TYPE_LIB;
|
||||
} else {
|
||||
mFileType = FILE_TYPE_UNKNOWN;
|
||||
}
|
||||
mSignature = signature;
|
||||
}
|
||||
|
||||
public @FileType int getFileType() {
|
||||
return mFileType;
|
||||
public @PackageInstaller.FileLocation int getLocation() {
|
||||
return mLocation;
|
||||
}
|
||||
|
||||
public @NonNull String getName() {
|
||||
return mFileName;
|
||||
return mName;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mFileSize;
|
||||
public long getLengthBytes() {
|
||||
return mLengthBytes;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getMetadata() {
|
||||
return mMetadata;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getSignature() {
|
||||
return mSignature;
|
||||
}
|
||||
|
||||
private InstallationFile(Parcel source) {
|
||||
mFileName = source.readString();
|
||||
mFileType = source.readInt();
|
||||
mFileSize = source.readLong();
|
||||
mLocation = source.readInt();
|
||||
mName = source.readString();
|
||||
mLengthBytes = source.readLong();
|
||||
mMetadata = source.createByteArray();
|
||||
mSignature = source.createByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,10 +78,11 @@ public final class InstallationFile implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mFileName);
|
||||
dest.writeInt(mFileType);
|
||||
dest.writeLong(mFileSize);
|
||||
dest.writeInt(mLocation);
|
||||
dest.writeString(mName);
|
||||
dest.writeLong(mLengthBytes);
|
||||
dest.writeByteArray(mMetadata);
|
||||
dest.writeByteArray(mSignature);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<InstallationFile> CREATOR =
|
||||
|
||||
@@ -29,6 +29,8 @@ package android.os.incremental;
|
||||
* @throws IllegalStateException the session is not an Incremental installation session.
|
||||
*/
|
||||
|
||||
import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
@@ -85,7 +87,7 @@ public final class IncrementalFileStorages {
|
||||
try {
|
||||
result = new IncrementalFileStorages(stageDir, incrementalManager, dataLoaderParams);
|
||||
for (InstallationFile file : addedFiles) {
|
||||
if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
|
||||
if (file.getLocation() == LOCATION_DATA_APP) {
|
||||
try {
|
||||
result.addApkFile(file);
|
||||
} catch (IOException e) {
|
||||
@@ -95,7 +97,7 @@ public final class IncrementalFileStorages {
|
||||
e);
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unknown file type: " + file.getFileType());
|
||||
throw new IOException("Unknown file location: " + file.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +149,8 @@ public final class IncrementalFileStorages {
|
||||
String apkName = apk.getName();
|
||||
File targetFile = Paths.get(stageDirPath, apkName).toFile();
|
||||
if (!targetFile.exists()) {
|
||||
mDefaultStorage.makeFile(apkName, apk.getSize(), null,
|
||||
apk.getMetadata(), 0, null, null, null);
|
||||
mDefaultStorage.makeFile(apkName, apk.getLengthBytes(), null, apk.getMetadata(),
|
||||
apk.getSignature());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,16 @@ public final class IncrementalManager {
|
||||
return nativeIsIncrementalPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns raw signature for file if it's on Incremental File System.
|
||||
* Unsafe, use only if you are sure what you are doing.
|
||||
*/
|
||||
public static @Nullable byte[] unsafeGetFileSignature(@NonNull String path) {
|
||||
return nativeUnsafeGetFileSignature(path);
|
||||
}
|
||||
|
||||
/* Native methods */
|
||||
private static native boolean nativeIsEnabled();
|
||||
private static native boolean nativeIsIncrementalPath(@NonNull String path);
|
||||
private static native byte[] nativeUnsafeGetFileSignature(@NonNull String path);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -169,10 +171,11 @@ public final class IncrementalStorage {
|
||||
* @param path Relative path of the new file.
|
||||
* @param size Size of the new file in bytes.
|
||||
* @param metadata Metadata bytes.
|
||||
* @param v4signatureBytes Serialized V4SignatureProto.
|
||||
*/
|
||||
public void makeFile(@NonNull String path, long size, @Nullable UUID id,
|
||||
@Nullable byte[] metadata, int hashAlgorithm, @Nullable byte[] rootHash,
|
||||
@Nullable byte[] additionalData, @Nullable byte[] signature) throws IOException {
|
||||
@Nullable byte[] metadata, @Nullable byte[] v4signatureBytes)
|
||||
throws IOException {
|
||||
try {
|
||||
if (id == null && metadata == null) {
|
||||
throw new IOException("File ID and metadata cannot both be null");
|
||||
@@ -181,13 +184,7 @@ public final class IncrementalStorage {
|
||||
params.size = size;
|
||||
params.metadata = (metadata == null ? new byte[0] : metadata);
|
||||
params.fileId = idToBytes(id);
|
||||
if (hashAlgorithm != 0 || signature != null) {
|
||||
params.signature = new IncrementalSignature();
|
||||
params.signature.hashAlgorithm = hashAlgorithm;
|
||||
params.signature.rootHash = rootHash;
|
||||
params.signature.additionalData = additionalData;
|
||||
params.signature.signature = signature;
|
||||
}
|
||||
params.signature = parseV4Signature(v4signatureBytes);
|
||||
int res = mService.makeFile(mId, path, params);
|
||||
if (res != 0) {
|
||||
throw new IOException("makeFile() failed with errno " + -res);
|
||||
@@ -197,6 +194,7 @@ public final class IncrementalStorage {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a file in Incremental storage. The content of the file is mapped from a range inside
|
||||
* a source file in the same storage.
|
||||
@@ -349,6 +347,37 @@ public final class IncrementalStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata object of an IncFs File.
|
||||
*
|
||||
* @param id The file id.
|
||||
* @return Byte array that contains metadata bytes.
|
||||
*/
|
||||
@Nullable
|
||||
public byte[] getFileMetadata(@NonNull UUID id) {
|
||||
try {
|
||||
final byte[] rawId = idToBytes(id);
|
||||
return mService.getMetadataById(mId, rawId);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the data loader service associated with the current storage to start data loader
|
||||
*
|
||||
* @return True if data loader is successfully started.
|
||||
*/
|
||||
public boolean startLoading() {
|
||||
try {
|
||||
return mService.startLoading(mId);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int UUID_BYTE_SIZE = 16;
|
||||
|
||||
/**
|
||||
@@ -386,35 +415,44 @@ public final class IncrementalStorage {
|
||||
return new UUID(msb, lsb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata object of an IncFs File.
|
||||
*
|
||||
* @param id The file id.
|
||||
* @return Byte array that contains metadata bytes.
|
||||
*/
|
||||
@Nullable
|
||||
public byte[] getFileMetadata(@NonNull UUID id) {
|
||||
try {
|
||||
final byte[] rawId = idToBytes(id);
|
||||
return mService.getMetadataById(mId, rawId);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static final int INCFS_HASH_SHA256 = 1;
|
||||
private static final int INCFS_MAX_HASH_SIZE = 32; // SHA256
|
||||
private static final int INCFS_MAX_ADD_DATA_SIZE = 128;
|
||||
|
||||
/**
|
||||
* Informs the data loader service associated with the current storage to start data loader
|
||||
*
|
||||
* @return True if data loader is successfully started.
|
||||
* Deserialize and validate v4 signature bytes.
|
||||
*/
|
||||
public boolean startLoading() {
|
||||
try {
|
||||
return mService.startLoading(mId);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
return false;
|
||||
private static IncrementalSignature parseV4Signature(@Nullable byte[] v4signatureBytes)
|
||||
throws IOException {
|
||||
if (v4signatureBytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final V4Signature signature;
|
||||
try (DataInputStream input = new DataInputStream(
|
||||
new ByteArrayInputStream(v4signatureBytes))) {
|
||||
signature = V4Signature.readFrom(input);
|
||||
}
|
||||
|
||||
final byte[] rootHash = signature.verityRootHash;
|
||||
final byte[] additionalData = signature.v3Digest;
|
||||
final byte[] pkcs7Signature = signature.pkcs7SignatureBlock;
|
||||
|
||||
if (rootHash.length != INCFS_MAX_HASH_SIZE) {
|
||||
throw new IOException("rootHash has to be " + INCFS_MAX_HASH_SIZE + " bytes");
|
||||
}
|
||||
if (additionalData.length > INCFS_MAX_ADD_DATA_SIZE) {
|
||||
throw new IOException(
|
||||
"additionalData has to be at most " + INCFS_MAX_ADD_DATA_SIZE + " bytes");
|
||||
}
|
||||
|
||||
IncrementalSignature result = new IncrementalSignature();
|
||||
result.hashAlgorithm = INCFS_HASH_SHA256;
|
||||
result.rootHash = rootHash;
|
||||
result.additionalData = additionalData;
|
||||
result.signature = pkcs7Signature;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
62
core/java/android/os/incremental/V4Signature.java
Normal file
62
core/java/android/os/incremental/V4Signature.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.os.incremental;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* V4 signature fields.
|
||||
* Keep in sync with APKSig master copy.
|
||||
* @hide
|
||||
*/
|
||||
public class V4Signature {
|
||||
public final byte[] verityRootHash;
|
||||
public final byte[] v3Digest;
|
||||
public final byte[] pkcs7SignatureBlock;
|
||||
|
||||
V4Signature(byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
|
||||
this.verityRootHash = verityRootHash;
|
||||
this.v3Digest = v3Digest;
|
||||
this.pkcs7SignatureBlock = pkcs7SignatureBlock;
|
||||
}
|
||||
|
||||
static byte[] readBytes(DataInputStream stream) throws IOException {
|
||||
byte[] result = new byte[stream.readInt()];
|
||||
stream.read(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static V4Signature readFrom(DataInputStream stream) throws IOException {
|
||||
byte[] verityRootHash = readBytes(stream);
|
||||
byte[] v3Digest = readBytes(stream);
|
||||
byte[] pkcs7SignatureBlock = readBytes(stream);
|
||||
return new V4Signature(verityRootHash, v3Digest, pkcs7SignatureBlock);
|
||||
}
|
||||
|
||||
static void writeBytes(DataOutputStream stream, byte[] bytes) throws IOException {
|
||||
stream.writeInt(bytes.length);
|
||||
stream.write(bytes);
|
||||
}
|
||||
|
||||
void writeTo(DataOutputStream stream) throws IOException {
|
||||
writeBytes(stream, this.verityRootHash);
|
||||
writeBytes(stream, this.v3Digest);
|
||||
writeBytes(stream, this.pkcs7SignatureBlock);
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public abstract class DataLoaderService extends Service {
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public @Nullable DataLoader onCreateDataLoader() {
|
||||
public @Nullable DataLoader onCreateDataLoader(@NonNull DataLoaderParams dataLoaderParams) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +37,28 @@ static jboolean nativeIsIncrementalPath(JNIEnv* env,
|
||||
return (jboolean)IncFs_IsIncFsPath(path.c_str());
|
||||
}
|
||||
|
||||
static const JNINativeMethod method_table[] = {
|
||||
{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
|
||||
{"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath},
|
||||
};
|
||||
static jbyteArray nativeUnsafeGetFileSignature(JNIEnv* env, jobject clazz, jstring javaPath) {
|
||||
ScopedUtfChars path(env, javaPath);
|
||||
|
||||
char signature[INCFS_MAX_SIGNATURE_SIZE];
|
||||
size_t size = sizeof(signature);
|
||||
if (IncFs_UnsafeGetSignatureByPath(path.c_str(), signature, &size) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jbyteArray result = env->NewByteArray(size);
|
||||
if (result != nullptr) {
|
||||
env->SetByteArrayRegion(result, 0, size, (const jbyte*)signature);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static const JNINativeMethod method_table[] = {{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
|
||||
{"nativeIsIncrementalPath", "(Ljava/lang/String;)Z",
|
||||
(void*)nativeIsIncrementalPath},
|
||||
{"nativeUnsafeGetFileSignature",
|
||||
"(Ljava/lang/String;)[B",
|
||||
(void*)nativeUnsafeGetFileSignature}};
|
||||
|
||||
int register_android_os_incremental_IncrementalManager(JNIEnv* env) {
|
||||
return jniRegisterNativeMethods(env, "android/os/incremental/IncrementalManager",
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.incremental.nativeadb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.pm.DataLoaderParams;
|
||||
import android.service.dataloader.DataLoaderService;
|
||||
|
||||
/** This code is used for testing only. */
|
||||
@@ -26,7 +28,7 @@ public class NativeAdbDataLoaderService extends DataLoaderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLoader onCreateDataLoader() {
|
||||
public DataLoader onCreateDataLoader(@NonNull DataLoaderParams dataLoaderParams) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package com.android.server.incremental;
|
||||
|
||||
import static android.content.pm.InstallationFile.FILE_TYPE_OBB;
|
||||
import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
|
||||
import static android.content.pm.PackageInstaller.LOCATION_MEDIA_OBB;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
@@ -183,10 +181,8 @@ public final class IncrementalManagerShellCommand extends ShellCommand {
|
||||
session = packageInstaller.openSession(sessionId);
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
InstallationFile file = installationFiles.get(i);
|
||||
final int location = file.getFileType() == FILE_TYPE_OBB ? LOCATION_MEDIA_OBB
|
||||
: LOCATION_DATA_APP;
|
||||
session.addFile(location, file.getName(), file.getSize(), file.getMetadata(),
|
||||
null);
|
||||
session.addFile(file.getLocation(), file.getName(), file.getLengthBytes(),
|
||||
file.getMetadata(), file.getSignature());
|
||||
}
|
||||
session.commit(localReceiver.getIntentSender());
|
||||
final Intent result = localReceiver.getResult();
|
||||
@@ -304,7 +300,8 @@ public final class IncrementalManagerShellCommand extends ShellCommand {
|
||||
}
|
||||
final byte[] metadata = String.valueOf(index).getBytes(
|
||||
StandardCharsets.UTF_8);
|
||||
fileList.add(new InstallationFile(name, size, metadata));
|
||||
fileList.add(
|
||||
new InstallationFile(LOCATION_DATA_APP, name, size, metadata, null));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -214,7 +214,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
|
||||
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
|
||||
private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
|
||||
private static final FileInfo[] EMPTY_FILE_INFO_ARRAY = {};
|
||||
private static final InstallationFile[] EMPTY_INSTALLATION_FILE_ARRAY = {};
|
||||
|
||||
private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
|
||||
|
||||
@@ -309,33 +309,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
@GuardedBy("mLock")
|
||||
private int mParentSessionId;
|
||||
|
||||
static class FileInfo {
|
||||
public final int location;
|
||||
public final String name;
|
||||
public final Long lengthBytes;
|
||||
public final byte[] metadata;
|
||||
public final byte[] signature;
|
||||
|
||||
public static FileInfo added(int location, String name, Long lengthBytes, byte[] metadata,
|
||||
byte[] signature) {
|
||||
return new FileInfo(location, name, lengthBytes, metadata, signature);
|
||||
}
|
||||
|
||||
public static FileInfo removed(int location, String name) {
|
||||
return new FileInfo(location, name, -1L, null, null);
|
||||
}
|
||||
|
||||
FileInfo(int location, String name, Long lengthBytes, byte[] metadata, byte[] signature) {
|
||||
this.location = location;
|
||||
this.name = name;
|
||||
this.lengthBytes = lengthBytes;
|
||||
this.metadata = metadata;
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ArrayList<FileInfo> mFiles = new ArrayList<>();
|
||||
private ArrayList<InstallationFile> mFiles = new ArrayList<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean mStagedSessionApplied;
|
||||
@@ -508,7 +483,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
|
||||
int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
|
||||
SessionParams params, long createdMillis,
|
||||
File stageDir, String stageCid, FileInfo[] files, boolean prepared,
|
||||
File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
|
||||
boolean committed, boolean sealed,
|
||||
@Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
|
||||
boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
|
||||
@@ -539,7 +514,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
this.mParentSessionId = parentSessionId;
|
||||
|
||||
if (files != null) {
|
||||
for (FileInfo file : files) {
|
||||
for (InstallationFile file : files) {
|
||||
mFiles.add(file);
|
||||
}
|
||||
}
|
||||
@@ -738,7 +713,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
|
||||
String[] result = new String[mFiles.size()];
|
||||
for (int i = 0, size = mFiles.size(); i < size; ++i) {
|
||||
result[i] = mFiles.get(i).name;
|
||||
result[i] = mFiles.get(i).getName();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -2425,7 +2400,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
assertCallerIsOwnerOrRootLocked();
|
||||
assertPreparedAndNotSealedLocked("addFile");
|
||||
|
||||
mFiles.add(FileInfo.added(location, name, lengthBytes, metadata, signature));
|
||||
mFiles.add(new InstallationFile(location, name, lengthBytes, metadata, signature));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2443,7 +2418,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
assertCallerIsOwnerOrRootLocked();
|
||||
assertPreparedAndNotSealedLocked("removeFile");
|
||||
|
||||
mFiles.add(FileInfo.removed(location, getRemoveMarkerName(name)));
|
||||
mFiles.add(new InstallationFile(location, getRemoveMarkerName(name), -1, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2461,17 +2436,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
final List<InstallationFile> addedFiles = new ArrayList<>(mFiles.size());
|
||||
for (FileInfo file : mFiles) {
|
||||
if (sAddedFilter.accept(new File(this.stageDir, file.name))) {
|
||||
addedFiles.add(new InstallationFile(
|
||||
file.name, file.lengthBytes, file.metadata));
|
||||
for (InstallationFile file : mFiles) {
|
||||
if (sAddedFilter.accept(new File(this.stageDir, file.getName()))) {
|
||||
addedFiles.add(file);
|
||||
}
|
||||
}
|
||||
final List<String> removedFiles = new ArrayList<>(mFiles.size());
|
||||
for (FileInfo file : mFiles) {
|
||||
if (sRemovedFilter.accept(new File(this.stageDir, file.name))) {
|
||||
String name = file.name.substring(
|
||||
0, file.name.length() - REMOVE_MARKER_EXTENSION.length());
|
||||
for (InstallationFile file : mFiles) {
|
||||
if (sRemovedFilter.accept(new File(this.stageDir, file.getName()))) {
|
||||
String name = file.getName().substring(
|
||||
0, file.getName().length() - REMOVE_MARKER_EXTENSION.length());
|
||||
removedFiles.add(name);
|
||||
}
|
||||
}
|
||||
@@ -2970,13 +2944,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
|
||||
out.endTag(null, TAG_CHILD_SESSION);
|
||||
}
|
||||
for (FileInfo fileInfo : mFiles) {
|
||||
for (InstallationFile file : mFiles) {
|
||||
out.startTag(null, TAG_SESSION_FILE);
|
||||
writeIntAttribute(out, ATTR_LOCATION, fileInfo.location);
|
||||
writeStringAttribute(out, ATTR_NAME, fileInfo.name);
|
||||
writeLongAttribute(out, ATTR_LENGTH_BYTES, fileInfo.lengthBytes);
|
||||
writeByteArrayAttribute(out, ATTR_METADATA, fileInfo.metadata);
|
||||
writeByteArrayAttribute(out, ATTR_SIGNATURE, fileInfo.signature);
|
||||
writeIntAttribute(out, ATTR_LOCATION, file.getLocation());
|
||||
writeStringAttribute(out, ATTR_NAME, file.getName());
|
||||
writeLongAttribute(out, ATTR_LENGTH_BYTES, file.getLengthBytes());
|
||||
writeByteArrayAttribute(out, ATTR_METADATA, file.getMetadata());
|
||||
writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature());
|
||||
out.endTag(null, TAG_SESSION_FILE);
|
||||
}
|
||||
}
|
||||
@@ -3088,7 +3062,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
List<String> grantedRuntimePermissions = new ArrayList<>();
|
||||
List<String> whitelistedRestrictedPermissions = new ArrayList<>();
|
||||
List<Integer> childSessionIds = new ArrayList<>();
|
||||
List<FileInfo> files = new ArrayList<>();
|
||||
List<InstallationFile> files = new ArrayList<>();
|
||||
int outerDepth = in.getDepth();
|
||||
int type;
|
||||
while ((type = in.next()) != XmlPullParser.END_DOCUMENT
|
||||
@@ -3107,7 +3081,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
|
||||
}
|
||||
if (TAG_SESSION_FILE.equals(in.getName())) {
|
||||
files.add(new FileInfo(
|
||||
files.add(new InstallationFile(
|
||||
readIntAttribute(in, ATTR_LOCATION, 0),
|
||||
readStringAttribute(in, ATTR_NAME),
|
||||
readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
|
||||
@@ -3135,16 +3109,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
|
||||
}
|
||||
|
||||
FileInfo[] fileInfosArray = null;
|
||||
InstallationFile[] fileArray = null;
|
||||
if (!files.isEmpty()) {
|
||||
fileInfosArray = files.toArray(EMPTY_FILE_INFO_ARRAY);
|
||||
fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY);
|
||||
}
|
||||
|
||||
InstallSource installSource = InstallSource.create(installInitiatingPackageName,
|
||||
installOriginatingPackageName, installerPackageName);
|
||||
return new PackageInstallerSession(callback, context, pm, sessionProvider,
|
||||
installerThread, stagingManager, sessionId, userId, installerUid,
|
||||
installSource, params, createdMillis, stageDir, stageCid, fileInfosArray,
|
||||
installSource, params, createdMillis, stageDir, stageCid, fileArray,
|
||||
prepared, committed, sealed, childSessionIdsArray, parentSessionId,
|
||||
isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
|
||||
}
|
||||
|
||||
@@ -1163,7 +1163,7 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
final InstallParams params = makeInstallParams();
|
||||
if (params.sessionParams.dataLoaderParams == null) {
|
||||
params.sessionParams.setDataLoaderParams(
|
||||
PackageManagerShellCommandDataLoader.getDataLoaderParams(this));
|
||||
PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
|
||||
}
|
||||
return doRunInstall(params);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
|
||||
|
||||
private static final String STDIN_PATH = "-";
|
||||
|
||||
static DataLoaderParams getDataLoaderParams(ShellCommand shellCommand) {
|
||||
private static String getDataLoaderParamsArgs(ShellCommand shellCommand) {
|
||||
int commandId;
|
||||
synchronized (sShellCommands) {
|
||||
// Clean up old references.
|
||||
@@ -78,8 +78,12 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
|
||||
sShellCommands.put(commandId, new WeakReference<>(shellCommand));
|
||||
}
|
||||
|
||||
final String args = SHELL_COMMAND_ID_PREFIX + commandId;
|
||||
return DataLoaderParams.forStreaming(new ComponentName(PACKAGE, CLASS), args);
|
||||
return SHELL_COMMAND_ID_PREFIX + commandId;
|
||||
}
|
||||
|
||||
static DataLoaderParams getStreamingDataLoaderParams(ShellCommand shellCommand) {
|
||||
return DataLoaderParams.forStreaming(new ComponentName(PACKAGE, CLASS),
|
||||
getDataLoaderParamsArgs(shellCommand));
|
||||
}
|
||||
|
||||
private static int extractShellCommandId(String args) {
|
||||
@@ -133,17 +137,17 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
for (InstallationFile fileInfo : addedFiles) {
|
||||
String filePath = new String(fileInfo.getMetadata(), StandardCharsets.UTF_8);
|
||||
for (InstallationFile file : addedFiles) {
|
||||
String filePath = new String(file.getMetadata(), StandardCharsets.UTF_8);
|
||||
if (STDIN_PATH.equals(filePath) || TextUtils.isEmpty(filePath)) {
|
||||
final ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(
|
||||
shellCommand.getInFileDescriptor());
|
||||
mConnector.writeData(fileInfo.getName(), 0, fileInfo.getSize(), inFd);
|
||||
mConnector.writeData(file.getName(), 0, file.getLengthBytes(), inFd);
|
||||
} else {
|
||||
ParcelFileDescriptor incomingFd = null;
|
||||
try {
|
||||
incomingFd = shellCommand.openFileForSystem(filePath, "r");
|
||||
mConnector.writeData(fileInfo.getName(), 0, incomingFd.getStatSize(),
|
||||
mConnector.writeData(file.getName(), 0, incomingFd.getStatSize(),
|
||||
incomingFd);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(incomingFd);
|
||||
@@ -159,7 +163,8 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLoaderService.DataLoader onCreateDataLoader() {
|
||||
public DataLoaderService.DataLoader onCreateDataLoader(
|
||||
@NonNull DataLoaderParams dataLoaderParams) {
|
||||
return new DataLoader();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,6 @@ public:
|
||||
}
|
||||
|
||||
RawMetadata getMetadata(StorageId storage, FileId node) const;
|
||||
std::string getSignatureData(StorageId storage, FileId node) const;
|
||||
|
||||
std::vector<std::string> listFiles(StorageId storage) const;
|
||||
bool startLoading(StorageId storage) const;
|
||||
|
||||
Reference in New Issue
Block a user