Merge "[incremental] data loader manager interface"
This commit is contained in:
27
Android.bp
27
Android.bp
@@ -803,10 +803,9 @@ filegroup {
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "incremental_data_loader_aidl",
|
||||
name: "dataloader_aidl",
|
||||
srcs: [
|
||||
"core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl",
|
||||
"core/java/android/service/incremental/IIncrementalDataLoaderService.aidl",
|
||||
"core/java/android/content/pm/IDataLoaderStatusListener.aidl",
|
||||
],
|
||||
path: "core/java",
|
||||
}
|
||||
@@ -815,7 +814,27 @@ aidl_interface {
|
||||
name: "libincremental_aidl",
|
||||
srcs: [
|
||||
":incremental_aidl",
|
||||
":incremental_data_loader_aidl",
|
||||
],
|
||||
imports: [
|
||||
"libdataloader_aidl",
|
||||
],
|
||||
backend: {
|
||||
java: {
|
||||
sdk_version: "28",
|
||||
},
|
||||
cpp: {
|
||||
enabled: true,
|
||||
},
|
||||
ndk: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
aidl_interface {
|
||||
name: "libdataloader_aidl",
|
||||
srcs: [
|
||||
":dataloader_aidl",
|
||||
],
|
||||
backend: {
|
||||
java: {
|
||||
|
||||
@@ -3427,7 +3427,6 @@ public abstract class Context {
|
||||
//@hide: TIME_DETECTOR_SERVICE,
|
||||
//@hide: TIME_ZONE_DETECTOR_SERVICE,
|
||||
PERMISSION_SERVICE,
|
||||
INCREMENTAL_SERVICE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ServiceName {}
|
||||
@@ -4969,6 +4968,13 @@ public abstract class Context {
|
||||
@SystemApi
|
||||
public static final String APP_INTEGRITY_SERVICE = "app_integrity";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve an
|
||||
* {@link android.content.pm.DataLoaderManager}.
|
||||
* @hide
|
||||
*/
|
||||
public static final String DATA_LOADER_MANAGER_SERVICE = "dataloadermanager";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve an
|
||||
* {@link android.os.incremental.IncrementalManager}.
|
||||
|
||||
@@ -4052,6 +4052,13 @@ public class Intent implements Parcelable, Cloneable {
|
||||
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
|
||||
|
||||
/**
|
||||
* Used for looking up a Data Loader Service providers.
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String ACTION_LOAD_DATA = "android.intent.action.LOAD_DATA";
|
||||
|
||||
/**
|
||||
* An int extra used with {@link #ACTION_SERVICE_STATE} which indicates voice registration
|
||||
* state.
|
||||
|
||||
87
core/java/android/content/pm/DataLoaderManager.java
Normal file
87
core/java/android/content/pm/DataLoaderManager.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.content.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* Data loader manager takes care of data loaders of different packages. It provides methods to
|
||||
* initialize a data loader binder service (binding and creating it), to return a binder of the data
|
||||
* loader binder service and to destroy a data loader binder service.
|
||||
* @see com.android.server.pm.DataLoaderManagerService
|
||||
* @hide
|
||||
*/
|
||||
public class DataLoaderManager {
|
||||
private static final String TAG = "DataLoaderManager";
|
||||
private final IDataLoaderManager mService;
|
||||
|
||||
public DataLoaderManager(IDataLoaderManager service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a data loader binder service and binds to it. This requires PackageManager.
|
||||
*
|
||||
* @param dataLoaderId ID for the new data loader binder service.
|
||||
* @param params Bundle that contains parameters to configure the data loader service.
|
||||
* Must contain:
|
||||
* key: "packageName", value: String, package name of data loader service
|
||||
* package;
|
||||
* key: "extras", value: Bundle, client-specific data structures
|
||||
*
|
||||
* @param listener Callback for the data loader service to report status back to the
|
||||
* caller.
|
||||
* @return false if 1) target ID collides with a data loader that is already bound to data
|
||||
* loader manager; 2) package name is not specified; 3) fails to find data loader package;
|
||||
* or 4) fails to bind to the specified data loader service, otherwise return true.
|
||||
*/
|
||||
public boolean initializeDataLoader(int dataLoaderId, @NonNull Bundle params,
|
||||
@NonNull IDataLoaderStatusListener listener) {
|
||||
try {
|
||||
return mService.initializeDataLoader(dataLoaderId, params, listener);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a binder interface of the data loader binder service, given its ID.
|
||||
*/
|
||||
@Nullable
|
||||
public IDataLoader getDataLoader(int dataLoaderId) {
|
||||
try {
|
||||
return mService.getDataLoader(dataLoaderId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the data loader binder service and removes it from data loader manager service.
|
||||
*/
|
||||
@Nullable
|
||||
public void destroyDataLoader(int dataLoaderId) {
|
||||
try {
|
||||
mService.destroyDataLoader(dataLoaderId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
core/java/android/content/pm/IDataLoader.aidl
Normal file
34
core/java/android/content/pm/IDataLoader.aidl
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.content.pm;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.content.pm.IDataLoaderStatusListener;
|
||||
import android.content.pm.InstallationFile;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO: update with new APIs
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IDataLoader {
|
||||
void create(int id, in Bundle params, IDataLoaderStatusListener listener);
|
||||
void start(in List<InstallationFile> fileInfos);
|
||||
void stop();
|
||||
void destroy();
|
||||
void onFileCreated(long inode, in byte[] metadata);
|
||||
}
|
||||
29
core/java/android/content/pm/IDataLoaderManager.aidl
Normal file
29
core/java/android/content/pm/IDataLoaderManager.aidl
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.content.pm;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.content.pm.IDataLoader;
|
||||
import android.content.pm.IDataLoaderStatusListener;
|
||||
import java.util.List;
|
||||
|
||||
/** @hide */
|
||||
interface IDataLoaderManager {
|
||||
boolean initializeDataLoader(int id, in Bundle params, IDataLoaderStatusListener listener);
|
||||
IDataLoader getDataLoader(int dataLoaderId);
|
||||
void destroyDataLoader(int dataLoaderId);
|
||||
}
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.incremental;
|
||||
package android.content.pm;
|
||||
|
||||
/**
|
||||
* Callbacks from DataLoaderService to IncrementalService to report data loader status.
|
||||
* Callbacks from a data loader binder service to report data loader status.
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IIncrementalDataLoaderStatusListener {
|
||||
oneway interface IDataLoaderStatusListener {
|
||||
/** Data loader status */
|
||||
const int DATA_LOADER_READY = 0;
|
||||
const int DATA_LOADER_NOT_READY = 1;
|
||||
@@ -31,6 +31,6 @@ oneway interface IIncrementalDataLoaderStatusListener {
|
||||
const int DATA_LOADER_CONNECTION_OK = 6;
|
||||
|
||||
/** Data loader status callback */
|
||||
void onStatusChanged(in int storageId, in int status);
|
||||
void onStatusChanged(in int dataLoaderId, in int status);
|
||||
}
|
||||
|
||||
23
core/java/android/content/pm/InstallationFile.aidl
Normal file
23
core/java/android/content/pm/InstallationFile.aidl
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.content.pm;
|
||||
|
||||
/**
|
||||
* Describes a file which is part of a package installation.
|
||||
*/
|
||||
parcelable InstallationFile;
|
||||
|
||||
118
core/java/android/content/pm/InstallationFile.java
Normal file
118
core/java/android/content/pm/InstallationFile.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.content.pm;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
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
|
||||
*/
|
||||
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;
|
||||
|
||||
@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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public @FileType int getFileType() {
|
||||
return mFileType;
|
||||
}
|
||||
|
||||
public @NonNull String getName() {
|
||||
return mFileName;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mFileSize;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getMetadata() {
|
||||
return mMetadata;
|
||||
}
|
||||
|
||||
private InstallationFile(Parcel source) {
|
||||
mFileName = source.readString();
|
||||
mFileType = source.readInt();
|
||||
mFileSize = source.readLong();
|
||||
mMetadata = source.createByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mFileName);
|
||||
dest.writeInt(mFileType);
|
||||
dest.writeLong(mFileSize);
|
||||
dest.writeByteArray(mMetadata);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<InstallationFile> CREATOR =
|
||||
new Creator<InstallationFile>() {
|
||||
public InstallationFile createFromParcel(Parcel source) {
|
||||
return new InstallationFile(source);
|
||||
}
|
||||
|
||||
public InstallationFile[] newArray(int size) {
|
||||
return new InstallationFile[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -18,7 +18,7 @@ package android.os.incremental;
|
||||
|
||||
import android.os.incremental.IncrementalFileSystemControlParcel;
|
||||
import android.os.incremental.IncrementalDataLoaderParamsParcel;
|
||||
import android.service.incremental.IIncrementalDataLoaderStatusListener;
|
||||
import android.content.pm.IDataLoaderStatusListener;
|
||||
|
||||
/**
|
||||
* Binder service to receive calls from native Incremental Service and handle Java tasks such as
|
||||
@@ -29,7 +29,7 @@ interface IIncrementalServiceProxy {
|
||||
boolean prepareDataLoader(int mountId,
|
||||
in IncrementalFileSystemControlParcel control,
|
||||
in IncrementalDataLoaderParamsParcel params,
|
||||
in IIncrementalDataLoaderStatusListener listener);
|
||||
in IDataLoaderStatusListener listener);
|
||||
boolean startDataLoader(int mountId);
|
||||
void showHealthBlockedUI(int mountId);
|
||||
void destroyDataLoader(int mountId);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.service.incremental;
|
||||
|
||||
import android.os.incremental.IncrementalDataLoaderParamsParcel;
|
||||
import android.os.incremental.IncrementalFileSystemControlParcel;
|
||||
import android.service.incremental.IIncrementalDataLoaderStatusListener;
|
||||
|
||||
/** @hide */
|
||||
oneway interface IIncrementalDataLoaderService {
|
||||
void createDataLoader(in int storageId,
|
||||
in IncrementalFileSystemControlParcel control,
|
||||
in IncrementalDataLoaderParamsParcel params,
|
||||
in IIncrementalDataLoaderStatusListener listener,
|
||||
in boolean start);
|
||||
void startDataLoader(in int storageId);
|
||||
void stopDataLoader(in int storageId);
|
||||
void destroyDataLoader(in int storageId);
|
||||
void onFileCreated(in int storageId, in long inode, in byte[] metadata);
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 com.android.server.pm;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IDataLoader;
|
||||
import android.content.pm.IDataLoaderManager;
|
||||
import android.content.pm.IDataLoaderStatusListener;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data loader manager service manages data loader binder services.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class DataLoaderManagerService extends SystemService {
|
||||
private static final String TAG = "DataLoaderManager";
|
||||
private final Context mContext;
|
||||
private final DataLoaderManagerBinderService mBinderService;
|
||||
private final Object mLock = new Object();
|
||||
@GuardedBy("mLock")
|
||||
private SparseArray<DataLoaderServiceConnection> mServiceConnections;
|
||||
|
||||
public DataLoaderManagerService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mBinderService = new DataLoaderManagerBinderService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.DATA_LOADER_MANAGER_SERVICE, mBinderService);
|
||||
}
|
||||
|
||||
final class DataLoaderManagerBinderService extends IDataLoaderManager.Stub {
|
||||
@Override
|
||||
public boolean initializeDataLoader(int dataLoaderId, Bundle params,
|
||||
IDataLoaderStatusListener listener) {
|
||||
synchronized (mLock) {
|
||||
if (mServiceConnections == null) {
|
||||
mServiceConnections = new SparseArray<>();
|
||||
}
|
||||
if (mServiceConnections.get(dataLoaderId) != null) {
|
||||
Slog.e(TAG, "Data loader of ID=" + dataLoaderId + " already exists.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
CharSequence packageNameSeq = params.getCharSequence("packageName");
|
||||
if (packageNameSeq == null) {
|
||||
Slog.e(TAG, "Must specify package name.");
|
||||
return false;
|
||||
}
|
||||
String packageName = packageNameSeq.toString();
|
||||
ComponentName dataLoaderComponent = getDataLoaderServiceName(packageName);
|
||||
if (dataLoaderComponent == null) {
|
||||
return false;
|
||||
}
|
||||
// Binds to the specific data loader service
|
||||
DataLoaderServiceConnection connection =
|
||||
new DataLoaderServiceConnection(dataLoaderId, params, listener);
|
||||
Intent intent = new Intent();
|
||||
intent.setComponent(dataLoaderComponent);
|
||||
if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
|
||||
UserHandle.of(UserHandle.getCallingUserId()))) {
|
||||
Slog.e(TAG, "Failed to bind to data loader binder service.");
|
||||
mContext.unbindService(connection);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ComponentName of the data loader service provider, given its package name.
|
||||
*
|
||||
* @param packageName the package name of the provider.
|
||||
* @return ComponentName of the data loader service provider. Null if provider not found.
|
||||
*/
|
||||
private @Nullable ComponentName getDataLoaderServiceName(String packageName) {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
Slog.e(TAG, "PackageManager is not available.");
|
||||
return null;
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_LOAD_DATA);
|
||||
intent.setPackage(packageName);
|
||||
List<ResolveInfo> services =
|
||||
pm.queryIntentServicesAsUser(intent, 0, UserHandle.getCallingUserId());
|
||||
if (services == null || services.isEmpty()) {
|
||||
Slog.e(TAG,
|
||||
"Failed to find data loader service provider in package " + packageName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO(b/136132412): better way to enable privileged data loaders in tests
|
||||
boolean checkLoader =
|
||||
android.os.SystemProperties.getBoolean("incremental.check_loader", false);
|
||||
int numServices = services.size();
|
||||
for (int i = 0; i < numServices; i++) {
|
||||
ResolveInfo ri = services.get(i);
|
||||
ComponentName componentName = new ComponentName(
|
||||
ri.serviceInfo.packageName, ri.serviceInfo.name);
|
||||
// There should only be one matching provider inside the given package.
|
||||
// If there's more than one, return the first one found.
|
||||
try {
|
||||
ApplicationInfo ai = pm.getApplicationInfo(componentName.getPackageName(), 0);
|
||||
if (checkLoader && !ai.isPrivilegedApp()) {
|
||||
Slog.w(TAG,
|
||||
"Data loader: " + componentName.getPackageName()
|
||||
+ " is not a privileged app, skipping.");
|
||||
continue;
|
||||
}
|
||||
return componentName;
|
||||
} catch (PackageManager.NameNotFoundException ex) {
|
||||
Slog.w(TAG,
|
||||
"Privileged data loader: " + componentName.getPackageName()
|
||||
+ " not found, skipping.");
|
||||
}
|
||||
|
||||
}
|
||||
Slog.e(TAG, "Didn't find any matching data loader service provider.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binder object of a data loader, specified by its ID.
|
||||
*/
|
||||
@Override
|
||||
public @Nullable IDataLoader getDataLoader(int dataLoaderId) {
|
||||
synchronized (mLock) {
|
||||
if (mServiceConnections == null) {
|
||||
return null;
|
||||
}
|
||||
DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
|
||||
dataLoaderId, null);
|
||||
if (serviceConnection == null) {
|
||||
return null;
|
||||
}
|
||||
return serviceConnection.getDataLoader();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a data loader binder service, specified by its ID.
|
||||
*/
|
||||
@Override
|
||||
public void destroyDataLoader(int dataLoaderId) {
|
||||
synchronized (mLock) {
|
||||
if (mServiceConnections == null) {
|
||||
return;
|
||||
}
|
||||
DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
|
||||
dataLoaderId, null);
|
||||
|
||||
if (serviceConnection == null) {
|
||||
return;
|
||||
}
|
||||
serviceConnection.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DataLoaderServiceConnection implements ServiceConnection {
|
||||
final int mId;
|
||||
final Bundle mParams;
|
||||
final IDataLoaderStatusListener mListener;
|
||||
IDataLoader mDataLoader;
|
||||
|
||||
DataLoaderServiceConnection(int id, Bundle params, IDataLoaderStatusListener listener) {
|
||||
mId = id;
|
||||
mParams = params;
|
||||
mListener = listener;
|
||||
mDataLoader = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
mDataLoader = IDataLoader.Stub.asInterface(service);
|
||||
synchronized (mLock) {
|
||||
mServiceConnections.append(mId, this);
|
||||
}
|
||||
try {
|
||||
mDataLoader.create(mId, mParams, mListener);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to create data loader service.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0) {
|
||||
remove();
|
||||
}
|
||||
|
||||
IDataLoader getDataLoader() {
|
||||
return mDataLoader;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
try {
|
||||
mDataLoader.destroy();
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
mContext.unbindService(this);
|
||||
}
|
||||
|
||||
private void remove() {
|
||||
synchronized (mLock) {
|
||||
mServiceConnections.remove(mId);
|
||||
if (mServiceConnections.size() == 0) {
|
||||
mServiceConnections = null;
|
||||
}
|
||||
}
|
||||
mParams.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user