diff options
| author | 2019-11-29 15:20:18 -0800 | |
|---|---|---|
| committer | 2019-12-04 11:00:23 -0800 | |
| commit | 6dd47b58c53acee91810cd2714b97aacbfbfec6a (patch) | |
| tree | 2d056e58407e47c742896c715cb011631f587a09 | |
| parent | 7c738c6ac83ab35ea5a910addf06835cfc7fe3ae (diff) | |
[incremental] data loader manager interface
Checking in the interface for data loader manager and installation
files in android.content.pm.
Copied from branch master-instamatic. TODO to update the code with
latest API design.
Test: builds
Change-Id: Ie87dd8b45dc18f538ddabf87e2899e958133ff04
| -rw-r--r-- | Android.bp | 27 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 8 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 7 | ||||
| -rw-r--r-- | core/java/android/content/pm/DataLoaderManager.java | 87 | ||||
| -rw-r--r-- | core/java/android/content/pm/IDataLoader.aidl | 34 | ||||
| -rw-r--r-- | core/java/android/content/pm/IDataLoaderManager.aidl | 29 | ||||
| -rw-r--r-- | core/java/android/content/pm/IDataLoaderStatusListener.aidl (renamed from core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl) | 8 | ||||
| -rw-r--r-- | core/java/android/content/pm/InstallationFile.aidl | 23 | ||||
| -rw-r--r-- | core/java/android/content/pm/InstallationFile.java | 118 | ||||
| -rw-r--r-- | core/java/android/os/incremental/IIncrementalServiceProxy.aidl | 4 | ||||
| -rw-r--r-- | core/java/android/service/incremental/IIncrementalDataLoaderService.aidl | 34 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/DataLoaderManagerService.java | 246 |
12 files changed, 580 insertions, 45 deletions
diff --git a/Android.bp b/Android.bp index a7ce9172bc95..967821ce5401 100644 --- a/Android.bp +++ b/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: { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 341b5206ba90..d370a380bc3b 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.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 {} @@ -4971,6 +4970,13 @@ public abstract class Context { /** * 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}. * @hide */ diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 40aca0ef2033..af7b98683219 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4053,6 +4053,13 @@ public class Intent implements Parcelable, Cloneable { 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. * @see android.telephony.ServiceState#STATE_EMERGENCY_ONLY diff --git a/core/java/android/content/pm/DataLoaderManager.java b/core/java/android/content/pm/DataLoaderManager.java new file mode 100644 index 000000000000..26880384e502 --- /dev/null +++ b/core/java/android/content/pm/DataLoaderManager.java @@ -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(); + } + } +} diff --git a/core/java/android/content/pm/IDataLoader.aidl b/core/java/android/content/pm/IDataLoader.aidl new file mode 100644 index 000000000000..60cc9ba9e141 --- /dev/null +++ b/core/java/android/content/pm/IDataLoader.aidl @@ -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); +} diff --git a/core/java/android/content/pm/IDataLoaderManager.aidl b/core/java/android/content/pm/IDataLoaderManager.aidl new file mode 100644 index 000000000000..f453c9b6c45f --- /dev/null +++ b/core/java/android/content/pm/IDataLoaderManager.aidl @@ -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); +}
\ No newline at end of file diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl index f04242dc6c02..a60d6ee2d28a 100644 --- a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl +++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl @@ -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); } diff --git a/core/java/android/content/pm/InstallationFile.aidl b/core/java/android/content/pm/InstallationFile.aidl new file mode 100644 index 000000000000..1edff9d6c7aa --- /dev/null +++ b/core/java/android/content/pm/InstallationFile.aidl @@ -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; + diff --git a/core/java/android/content/pm/InstallationFile.java b/core/java/android/content/pm/InstallationFile.java new file mode 100644 index 000000000000..ac5fd1e41075 --- /dev/null +++ b/core/java/android/content/pm/InstallationFile.java @@ -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]; + } + }; + +} diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl index 12740eaf3425..ffff52e5aac9 100644 --- a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl +++ b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl @@ -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); diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl deleted file mode 100644 index 723fc594bd72..000000000000 --- a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl +++ /dev/null @@ -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); -} diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java new file mode 100644 index 000000000000..0719797ed85a --- /dev/null +++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java @@ -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(); + } + } +} |