2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.pm;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.ServiceConnection;
23 import android.content.pm.EphemeralResolveInfo;
24 import android.os.Build;
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.os.IRemoteCallback;
28 import android.os.RemoteException;
29 import android.os.SystemClock;
30 import android.os.UserHandle;
31 import android.util.TimedRemoteCaller;
33 import com.android.internal.app.EphemeralResolverService;
34 import com.android.internal.app.IEphemeralResolver;
36 import java.io.FileDescriptor;
37 import java.io.PrintWriter;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.concurrent.TimeoutException;
43 * Represents a remote ephemeral resolver. It is responsible for binding to the remote
44 * service and handling all interactions in a timely manner.
47 final class EphemeralResolverConnection {
48 // This is running in a critical section and the timeout must be sufficiently low
49 private static final long BIND_SERVICE_TIMEOUT_MS =
50 ("eng".equals(Build.TYPE)) ? 300 : 200;
52 private final Object mLock = new Object();
53 private final GetEphemeralResolveInfoCaller mGetEphemeralResolveInfoCaller =
54 new GetEphemeralResolveInfoCaller();
55 private final ServiceConnection mServiceConnection = new MyServiceConnection();
56 private final Context mContext;
57 /** Intent used to bind to the service */
58 private final Intent mIntent;
60 private IEphemeralResolver mRemoteInstance;
62 public EphemeralResolverConnection(Context context, ComponentName componentName) {
64 mIntent = new Intent().setComponent(componentName);
67 public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
68 int hashPrefix[], int prefixMask) {
69 throwIfCalledOnMainThread();
71 return mGetEphemeralResolveInfoCaller.getEphemeralResolveInfoList(
72 getRemoteInstanceLazy(), hashPrefix, prefixMask);
73 } catch (RemoteException re) {
74 } catch (TimeoutException te) {
76 synchronized (mLock) {
83 public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
84 synchronized (mLock) {
85 pw.append(prefix).append("bound=")
86 .append((mRemoteInstance != null) ? "true" : "false").println();
91 getRemoteInstanceLazy().asBinder().dump(fd, new String[] { prefix });
92 } catch (TimeoutException te) {
94 } catch (RemoteException re) {
100 private IEphemeralResolver getRemoteInstanceLazy() throws TimeoutException {
101 synchronized (mLock) {
102 if (mRemoteInstance != null) {
103 return mRemoteInstance;
106 return mRemoteInstance;
110 private void bindLocked() throws TimeoutException {
111 if (mRemoteInstance != null) {
115 mContext.bindServiceAsUser(mIntent, mServiceConnection,
116 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.SYSTEM);
118 final long startMillis = SystemClock.uptimeMillis();
120 if (mRemoteInstance != null) {
123 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
124 final long remainingMillis = BIND_SERVICE_TIMEOUT_MS - elapsedMillis;
125 if (remainingMillis <= 0) {
126 throw new TimeoutException("Didn't bind to resolver in time.");
129 mLock.wait(remainingMillis);
130 } catch (InterruptedException ie) {
138 private void throwIfCalledOnMainThread() {
139 if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
140 throw new RuntimeException("Cannot invoke on the main thread");
144 private final class MyServiceConnection implements ServiceConnection {
146 public void onServiceConnected(ComponentName name, IBinder service) {
147 synchronized (mLock) {
148 mRemoteInstance = IEphemeralResolver.Stub.asInterface(service);
154 public void onServiceDisconnected(ComponentName name) {
155 synchronized (mLock) {
156 mRemoteInstance = null;
161 private static final class GetEphemeralResolveInfoCaller
162 extends TimedRemoteCaller<List<EphemeralResolveInfo>> {
163 private final IRemoteCallback mCallback;
165 public GetEphemeralResolveInfoCaller() {
166 super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
167 mCallback = new IRemoteCallback.Stub() {
169 public void sendResult(Bundle data) throws RemoteException {
170 final ArrayList<EphemeralResolveInfo> resolveList =
171 data.getParcelableArrayList(
172 EphemeralResolverService.EXTRA_RESOLVE_INFO);
174 data.getInt(EphemeralResolverService.EXTRA_SEQUENCE, -1);
175 onRemoteMethodResult(resolveList, sequence);
180 public List<EphemeralResolveInfo> getEphemeralResolveInfoList(
181 IEphemeralResolver target, int hashPrefix[], int prefixMask)
182 throws RemoteException, TimeoutException {
183 final int sequence = onBeforeRemoteCall();
184 target.getEphemeralResolveInfoList(mCallback, hashPrefix, prefixMask, sequence);
185 return getResultTimed(sequence);