blob: 0dfea7fd5f96c4b7243e4698d1879e6a06d53d40 [file] [log] [blame]
Songchun Fan6dd47b52019-11-29 15:20:18 -08001/*
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
17package com.android.server.pm;
18
19import android.annotation.Nullable;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.ServiceConnection;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.IDataLoader;
26import android.content.pm.IDataLoaderManager;
27import android.content.pm.IDataLoaderStatusListener;
28import android.content.pm.PackageManager;
29import android.content.pm.ResolveInfo;
30import android.os.Bundle;
31import android.os.IBinder;
32import android.os.RemoteException;
33import android.os.UserHandle;
34import android.util.Slog;
35import android.util.SparseArray;
36
37import com.android.internal.annotations.GuardedBy;
38import com.android.server.SystemService;
39
40import java.util.List;
41
42/**
43 * Data loader manager service manages data loader binder services.
44 *
45 * @hide
46 */
47public class DataLoaderManagerService extends SystemService {
48 private static final String TAG = "DataLoaderManager";
49 private final Context mContext;
50 private final DataLoaderManagerBinderService mBinderService;
51 private final Object mLock = new Object();
52 @GuardedBy("mLock")
53 private SparseArray<DataLoaderServiceConnection> mServiceConnections;
54
55 public DataLoaderManagerService(Context context) {
56 super(context);
57 mContext = context;
58 mBinderService = new DataLoaderManagerBinderService();
59 }
60
61 @Override
62 public void onStart() {
63 publishBinderService(Context.DATA_LOADER_MANAGER_SERVICE, mBinderService);
64 }
65
66 final class DataLoaderManagerBinderService extends IDataLoaderManager.Stub {
67 @Override
68 public boolean initializeDataLoader(int dataLoaderId, Bundle params,
69 IDataLoaderStatusListener listener) {
70 synchronized (mLock) {
71 if (mServiceConnections == null) {
72 mServiceConnections = new SparseArray<>();
73 }
74 if (mServiceConnections.get(dataLoaderId) != null) {
75 Slog.e(TAG, "Data loader of ID=" + dataLoaderId + " already exists.");
76 return false;
77 }
78 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080079 ComponentName componentName = params.getParcelable("componentName");
80 if (componentName == null) {
81 Slog.e(TAG, "Must specify component name.");
Songchun Fan6dd47b52019-11-29 15:20:18 -080082 return false;
83 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080084 ComponentName dataLoaderComponent = resolveDataLoaderComponentName(componentName);
Songchun Fan6dd47b52019-11-29 15:20:18 -080085 if (dataLoaderComponent == null) {
86 return false;
87 }
88 // Binds to the specific data loader service
89 DataLoaderServiceConnection connection =
90 new DataLoaderServiceConnection(dataLoaderId, params, listener);
91 Intent intent = new Intent();
92 intent.setComponent(dataLoaderComponent);
93 if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
94 UserHandle.of(UserHandle.getCallingUserId()))) {
95 Slog.e(TAG, "Failed to bind to data loader binder service.");
96 mContext.unbindService(connection);
97 return false;
98 }
99 return true;
100 }
101
102 /**
103 * Find the ComponentName of the data loader service provider, given its package name.
104 *
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800105 * @param componentName the name of the provider.
Songchun Fan6dd47b52019-11-29 15:20:18 -0800106 * @return ComponentName of the data loader service provider. Null if provider not found.
107 */
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800108 private @Nullable ComponentName resolveDataLoaderComponentName(
109 ComponentName componentName) {
Songchun Fan6dd47b52019-11-29 15:20:18 -0800110 final PackageManager pm = mContext.getPackageManager();
111 if (pm == null) {
112 Slog.e(TAG, "PackageManager is not available.");
113 return null;
114 }
115 Intent intent = new Intent(Intent.ACTION_LOAD_DATA);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800116 intent.setComponent(componentName);
Songchun Fan6dd47b52019-11-29 15:20:18 -0800117 List<ResolveInfo> services =
118 pm.queryIntentServicesAsUser(intent, 0, UserHandle.getCallingUserId());
119 if (services == null || services.isEmpty()) {
120 Slog.e(TAG,
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800121 "Failed to find data loader service provider in " + componentName);
Songchun Fan6dd47b52019-11-29 15:20:18 -0800122 return null;
123 }
124
125 // TODO(b/136132412): better way to enable privileged data loaders in tests
126 boolean checkLoader =
127 android.os.SystemProperties.getBoolean("incremental.check_loader", false);
128 int numServices = services.size();
129 for (int i = 0; i < numServices; i++) {
130 ResolveInfo ri = services.get(i);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800131 ComponentName resolved = new ComponentName(
Songchun Fan6dd47b52019-11-29 15:20:18 -0800132 ri.serviceInfo.packageName, ri.serviceInfo.name);
133 // There should only be one matching provider inside the given package.
134 // If there's more than one, return the first one found.
135 try {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800136 ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
Songchun Fan6dd47b52019-11-29 15:20:18 -0800137 if (checkLoader && !ai.isPrivilegedApp()) {
138 Slog.w(TAG,
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800139 "Data loader: " + resolved + " is not a privileged app, skipping.");
Songchun Fan6dd47b52019-11-29 15:20:18 -0800140 continue;
141 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800142 return resolved;
Songchun Fan6dd47b52019-11-29 15:20:18 -0800143 } catch (PackageManager.NameNotFoundException ex) {
144 Slog.w(TAG,
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800145 "Privileged data loader: " + resolved + " not found, skipping.");
Songchun Fan6dd47b52019-11-29 15:20:18 -0800146 }
147
148 }
149 Slog.e(TAG, "Didn't find any matching data loader service provider.");
150 return null;
151 }
152
153 /**
154 * Returns the binder object of a data loader, specified by its ID.
155 */
156 @Override
157 public @Nullable IDataLoader getDataLoader(int dataLoaderId) {
158 synchronized (mLock) {
159 if (mServiceConnections == null) {
160 return null;
161 }
162 DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
163 dataLoaderId, null);
164 if (serviceConnection == null) {
165 return null;
166 }
167 return serviceConnection.getDataLoader();
168 }
169 }
170
171 /**
172 * Destroys a data loader binder service, specified by its ID.
173 */
174 @Override
175 public void destroyDataLoader(int dataLoaderId) {
176 synchronized (mLock) {
177 if (mServiceConnections == null) {
178 return;
179 }
180 DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
181 dataLoaderId, null);
182
183 if (serviceConnection == null) {
184 return;
185 }
186 serviceConnection.destroy();
187 }
188 }
189 }
190
191 class DataLoaderServiceConnection implements ServiceConnection {
192 final int mId;
193 final Bundle mParams;
194 final IDataLoaderStatusListener mListener;
195 IDataLoader mDataLoader;
196
197 DataLoaderServiceConnection(int id, Bundle params, IDataLoaderStatusListener listener) {
198 mId = id;
199 mParams = params;
200 mListener = listener;
201 mDataLoader = null;
202 }
203
204 @Override
205 public void onServiceConnected(ComponentName className, IBinder service) {
206 mDataLoader = IDataLoader.Stub.asInterface(service);
207 synchronized (mLock) {
208 mServiceConnections.append(mId, this);
209 }
210 try {
211 mDataLoader.create(mId, mParams, mListener);
212 } catch (RemoteException e) {
213 Slog.e(TAG, "Failed to create data loader service.", e);
214 }
215 }
216
217 @Override
218 public void onServiceDisconnected(ComponentName arg0) {
219 remove();
220 }
221
222 IDataLoader getDataLoader() {
223 return mDataLoader;
224 }
225
226 void destroy() {
227 try {
228 mDataLoader.destroy();
229 } catch (RemoteException ignored) {
230 }
231 mContext.unbindService(this);
232 }
233
234 private void remove() {
235 synchronized (mLock) {
236 mServiceConnections.remove(mId);
237 if (mServiceConnections.size() == 0) {
238 mServiceConnections = null;
239 }
240 }
241 mParams.clear();
242 }
243 }
244}