blob: 01e0622063cd20fffbcc691405aacb909ec2cf9d [file] [log] [blame]
Adam Powelld25267c2015-06-05 18:02:21 -07001/*
2 * Copyright (C) 2015 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
17
18package com.android.internal.app;
19
20import android.app.usage.UsageStats;
Adam Powelld25267c2015-06-05 18:02:21 -070021import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
shafik6cbef192018-12-27 14:14:58 +000024import android.content.ServiceConnection;
Adam Powelld25267c2015-06-05 18:02:21 -070025import android.content.pm.ApplicationInfo;
Adam Powelld25267c2015-06-05 18:02:21 -070026import android.content.pm.PackageManager;
Kang Libbced1c2017-04-05 12:30:55 -070027import android.content.pm.PackageManager.NameNotFoundException;
Adam Powelld25267c2015-06-05 18:02:21 -070028import android.content.pm.ResolveInfo;
Kang Li2c571892017-07-05 14:47:32 -070029import android.metrics.LogMaker;
Kang Libbced1c2017-04-05 12:30:55 -070030import android.os.IBinder;
Kang Libbced1c2017-04-05 12:30:55 -070031import android.os.Message;
32import android.os.RemoteException;
Adam Powelld25267c2015-06-05 18:02:21 -070033import android.os.UserHandle;
Kang Libbced1c2017-04-05 12:30:55 -070034import android.service.resolver.IResolverRankerResult;
shafik6cbef192018-12-27 14:14:58 +000035import android.service.resolver.IResolverRankerService;
Kang Libbced1c2017-04-05 12:30:55 -070036import android.service.resolver.ResolverRankerService;
37import android.service.resolver.ResolverTarget;
Adam Powelld25267c2015-06-05 18:02:21 -070038import android.util.Log;
shafik6cbef192018-12-27 14:14:58 +000039
Adam Powelld25267c2015-06-05 18:02:21 -070040import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
Kang Li2c571892017-07-05 14:47:32 -070041import com.android.internal.logging.MetricsLogger;
42import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Adam Powelld25267c2015-06-05 18:02:21 -070043
44import java.text.Collator;
45import java.util.ArrayList;
Adam Powelld25267c2015-06-05 18:02:21 -070046import java.util.LinkedHashMap;
47import java.util.List;
48import java.util.Map;
shafik6cbef192018-12-27 14:14:58 +000049import java.util.concurrent.CountDownLatch;
50import java.util.concurrent.TimeUnit;
Adam Powelld25267c2015-06-05 18:02:21 -070051
52/**
George Hodulik30f0c6f2019-03-20 18:23:23 -070053 * Ranks and compares packages based on usage stats and uses the {@link ResolverRankerService}.
Adam Powelld25267c2015-06-05 18:02:21 -070054 */
George Hodulik30f0c6f2019-03-20 18:23:23 -070055class ResolverRankerServiceResolverComparator extends AbstractResolverComparator {
56 private static final String TAG = "RRSResolverComparator";
Adam Powelld25267c2015-06-05 18:02:21 -070057
Adam Powell06413942015-06-11 10:08:03 -070058 private static final boolean DEBUG = false;
Adam Powelld25267c2015-06-05 18:02:21 -070059
Adam Powell23882512016-01-29 10:21:00 -080060 // One week
61 private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 7;
Adam Powelld25267c2015-06-05 18:02:21 -070062
63 private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12;
64
Adam Powellbba00302016-02-03 16:01:09 -080065 private static final float RECENCY_MULTIPLIER = 2.f;
Adam Powelld25267c2015-06-05 18:02:21 -070066
Kang Libbced1c2017-04-05 12:30:55 -070067 // timeout for establishing connections with a ResolverRankerService.
68 private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200;
Kang Lia2c7774d2016-12-20 09:39:34 -080069
Adam Powelld25267c2015-06-05 18:02:21 -070070 private final Collator mCollator;
Adam Powelld25267c2015-06-05 18:02:21 -070071 private final Map<String, UsageStats> mStats;
72 private final long mCurrentTime;
73 private final long mSinceTime;
Kang Libbced1c2017-04-05 12:30:55 -070074 private final LinkedHashMap<ComponentName, ResolverTarget> mTargetsDict = new LinkedHashMap<>();
Adam Powelld25267c2015-06-05 18:02:21 -070075 private final String mReferrerPackage;
Kang Libbced1c2017-04-05 12:30:55 -070076 private final Object mLock = new Object();
77 private ArrayList<ResolverTarget> mTargets;
Kang Li53b43142016-11-14 14:38:25 -080078 private String mAction;
Kang Li2c571892017-07-05 14:47:32 -070079 private ComponentName mResolvedRankerName;
80 private ComponentName mRankerServiceName;
Kang Libbced1c2017-04-05 12:30:55 -070081 private IResolverRankerService mRanker;
82 private ResolverRankerServiceConnection mConnection;
Kang Libbced1c2017-04-05 12:30:55 -070083 private Context mContext;
84 private CountDownLatch mConnectSignal;
Adam Powelld25267c2015-06-05 18:02:21 -070085
George Hodulik30f0c6f2019-03-20 18:23:23 -070086 public ResolverRankerServiceResolverComparator(Context context, Intent intent,
87 String referrerPackage, AfterCompute afterCompute) {
George Hodulik93562442019-03-21 17:35:23 -070088 super(context, intent);
Adam Powelld25267c2015-06-05 18:02:21 -070089 mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
Adam Powelld25267c2015-06-05 18:02:21 -070090 mReferrerPackage = referrerPackage;
Kang Libbced1c2017-04-05 12:30:55 -070091 mContext = context;
Adam Powelld25267c2015-06-05 18:02:21 -070092
Adam Powelld25267c2015-06-05 18:02:21 -070093 mCurrentTime = System.currentTimeMillis();
94 mSinceTime = mCurrentTime - USAGE_STATS_PERIOD;
95 mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime);
Kang Li53b43142016-11-14 14:38:25 -080096 mAction = intent.getAction();
Kang Li2c571892017-07-05 14:47:32 -070097 mRankerServiceName = new ComponentName(mContext, this.getClass());
George Hodulikc681ce42019-04-12 17:10:31 -070098 setCallBack(afterCompute);
Kang Li9fa2a2c2017-01-06 13:33:24 -080099 }
100
George Hodulik1f5d9bf2019-04-29 14:55:48 -0700101 @Override
102 public void handleResultMessage(Message msg) {
103 if (msg.what != RANKER_SERVICE_RESULT) {
104 return;
105 }
George Hodulik3f399f22019-04-26 16:17:54 -0700106 if (msg.obj == null) {
107 Log.e(TAG, "Receiving null prediction results.");
108 return;
109 }
George Hodulik1f5d9bf2019-04-29 14:55:48 -0700110 final List<ResolverTarget> receivedTargets = (List<ResolverTarget>) msg.obj;
111 if (receivedTargets != null && mTargets != null
112 && receivedTargets.size() == mTargets.size()) {
113 final int size = mTargets.size();
114 boolean isUpdated = false;
115 for (int i = 0; i < size; ++i) {
116 final float predictedProb =
117 receivedTargets.get(i).getSelectProbability();
118 if (predictedProb != mTargets.get(i).getSelectProbability()) {
119 mTargets.get(i).setSelectProbability(predictedProb);
120 isUpdated = true;
121 }
122 }
123 if (isUpdated) {
124 mRankerServiceName = mResolvedRankerName;
125 }
126 } else {
127 Log.e(TAG, "Sizes of sent and received ResolverTargets diff.");
128 }
129 }
130
Kang Libbced1c2017-04-05 12:30:55 -0700131 // compute features for each target according to usage stats of targets.
George Hodulik30f0c6f2019-03-20 18:23:23 -0700132 @Override
George Hodulik1f5d9bf2019-04-29 14:55:48 -0700133 public void doCompute(List<ResolvedComponentInfo> targets) {
Adam Powelld25267c2015-06-05 18:02:21 -0700134 final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
135
Kang Libbced1c2017-04-05 12:30:55 -0700136 float mostRecencyScore = 1.0f;
137 float mostTimeSpentScore = 1.0f;
138 float mostLaunchScore = 1.0f;
139 float mostChooserScore = 1.0f;
Adam Powelld25267c2015-06-05 18:02:21 -0700140
141 for (ResolvedComponentInfo target : targets) {
Kang Libbced1c2017-04-05 12:30:55 -0700142 final ResolverTarget resolverTarget = new ResolverTarget();
143 mTargetsDict.put(target.name, resolverTarget);
Adam Powelld25267c2015-06-05 18:02:21 -0700144 final UsageStats pkStats = mStats.get(target.name.getPackageName());
145 if (pkStats != null) {
146 // Only count recency for apps that weren't the caller
147 // since the caller is always the most recent.
148 // Persistent processes muck this up, so omit them too.
149 if (!target.name.getPackageName().equals(mReferrerPackage)
150 && !isPersistentProcess(target)) {
Kang Libbced1c2017-04-05 12:30:55 -0700151 final float recencyScore =
152 (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0);
153 resolverTarget.setRecencyScore(recencyScore);
154 if (recencyScore > mostRecencyScore) {
155 mostRecencyScore = recencyScore;
Adam Powelld25267c2015-06-05 18:02:21 -0700156 }
157 }
Kang Libbced1c2017-04-05 12:30:55 -0700158 final float timeSpentScore = (float) pkStats.getTotalTimeInForeground();
159 resolverTarget.setTimeSpentScore(timeSpentScore);
160 if (timeSpentScore > mostTimeSpentScore) {
161 mostTimeSpentScore = timeSpentScore;
Adam Powelld25267c2015-06-05 18:02:21 -0700162 }
Kang Libbced1c2017-04-05 12:30:55 -0700163 final float launchScore = (float) pkStats.mLaunchCount;
164 resolverTarget.setLaunchScore(launchScore);
165 if (launchScore > mostLaunchScore) {
166 mostLaunchScore = launchScore;
Adam Powelld25267c2015-06-05 18:02:21 -0700167 }
Kang Li53b43142016-11-14 14:38:25 -0800168
Kang Libbced1c2017-04-05 12:30:55 -0700169 float chooserScore = 0.0f;
Kang Li53b43142016-11-14 14:38:25 -0800170 if (pkStats.mChooserCounts != null && mAction != null
171 && pkStats.mChooserCounts.get(mAction) != null) {
Kang Libbced1c2017-04-05 12:30:55 -0700172 chooserScore = (float) pkStats.mChooserCounts.get(mAction)
173 .getOrDefault(mContentType, 0);
Kang Li9fa2a2c2017-01-06 13:33:24 -0800174 if (mAnnotations != null) {
175 final int size = mAnnotations.length;
176 for (int i = 0; i < size; i++) {
Kang Libbced1c2017-04-05 12:30:55 -0700177 chooserScore += (float) pkStats.mChooserCounts.get(mAction)
Kang Li9fa2a2c2017-01-06 13:33:24 -0800178 .getOrDefault(mAnnotations[i], 0);
179 }
180 }
Kang Li53b43142016-11-14 14:38:25 -0800181 }
182 if (DEBUG) {
183 if (mAction == null) {
184 Log.d(TAG, "Action type is null");
185 } else {
186 Log.d(TAG, "Chooser Count of " + mAction + ":" +
Kang Libbced1c2017-04-05 12:30:55 -0700187 target.name.getPackageName() + " is " +
188 Float.toString(chooserScore));
Kang Li53b43142016-11-14 14:38:25 -0800189 }
190 }
Kang Libbced1c2017-04-05 12:30:55 -0700191 resolverTarget.setChooserScore(chooserScore);
192 if (chooserScore > mostChooserScore) {
193 mostChooserScore = chooserScore;
Kang Li53b43142016-11-14 14:38:25 -0800194 }
Adam Powelld25267c2015-06-05 18:02:21 -0700195 }
196 }
197
Adam Powelld25267c2015-06-05 18:02:21 -0700198 if (DEBUG) {
Kang Libbced1c2017-04-05 12:30:55 -0700199 Log.d(TAG, "compute - mostRecencyScore: " + mostRecencyScore
200 + " mostTimeSpentScore: " + mostTimeSpentScore
201 + " mostLaunchScore: " + mostLaunchScore
202 + " mostChooserScore: " + mostChooserScore);
Adam Powelld25267c2015-06-05 18:02:21 -0700203 }
204
Kang Libbced1c2017-04-05 12:30:55 -0700205 mTargets = new ArrayList<>(mTargetsDict.values());
206 for (ResolverTarget target : mTargets) {
207 final float recency = target.getRecencyScore() / mostRecencyScore;
208 setFeatures(target, recency * recency * RECENCY_MULTIPLIER,
209 target.getLaunchScore() / mostLaunchScore,
210 target.getTimeSpentScore() / mostTimeSpentScore,
211 target.getChooserScore() / mostChooserScore);
212 addDefaultSelectProbability(target);
Adam Powelld25267c2015-06-05 18:02:21 -0700213 if (DEBUG) {
Kang Lia2c7774d2016-12-20 09:39:34 -0800214 Log.d(TAG, "Scores: " + target);
Adam Powelld25267c2015-06-05 18:02:21 -0700215 }
216 }
Kang Libbced1c2017-04-05 12:30:55 -0700217 predictSelectProbabilities(mTargets);
Adam Powelld25267c2015-06-05 18:02:21 -0700218 }
219
220 @Override
George Hodulik93562442019-03-21 17:35:23 -0700221 public int compare(ResolveInfo lhs, ResolveInfo rhs) {
Matt Pietaldf634cc2019-03-13 09:55:28 -0400222 if (mStats != null) {
223 final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
224 lhs.activityInfo.packageName, lhs.activityInfo.name));
225 final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
226 rhs.activityInfo.packageName, rhs.activityInfo.name));
Adam Powelld25267c2015-06-05 18:02:21 -0700227
Matt Pietaldf634cc2019-03-13 09:55:28 -0400228 if (lhsTarget != null && rhsTarget != null) {
229 final int selectProbabilityDiff = Float.compare(
Kang Libbced1c2017-04-05 12:30:55 -0700230 rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
Kang Li53b43142016-11-14 14:38:25 -0800231
Matt Pietaldf634cc2019-03-13 09:55:28 -0400232 if (selectProbabilityDiff != 0) {
233 return selectProbabilityDiff > 0 ? 1 : -1;
Adam Powell23882512016-01-29 10:21:00 -0800234 }
Adam Powelld25267c2015-06-05 18:02:21 -0700235 }
236 }
237
238 CharSequence sa = lhs.loadLabel(mPm);
239 if (sa == null) sa = lhs.activityInfo.name;
240 CharSequence sb = rhs.loadLabel(mPm);
241 if (sb == null) sb = rhs.activityInfo.name;
242
243 return mCollator.compare(sa.toString().trim(), sb.toString().trim());
244 }
245
George Hodulik30f0c6f2019-03-20 18:23:23 -0700246 @Override
Adam Powella182e452015-07-06 16:57:56 -0700247 public float getScore(ComponentName name) {
Kang Libbced1c2017-04-05 12:30:55 -0700248 final ResolverTarget target = mTargetsDict.get(name);
Adam Powella182e452015-07-06 16:57:56 -0700249 if (target != null) {
Kang Libbced1c2017-04-05 12:30:55 -0700250 return target.getSelectProbability();
Adam Powella182e452015-07-06 16:57:56 -0700251 }
252 return 0;
253 }
254
Kang Libbced1c2017-04-05 12:30:55 -0700255 // update ranking model when the connection to it is valid.
George Hodulik30f0c6f2019-03-20 18:23:23 -0700256 @Override
Kang Lia2c7774d2016-12-20 09:39:34 -0800257 public void updateModel(ComponentName componentName) {
Kang Libbced1c2017-04-05 12:30:55 -0700258 synchronized (mLock) {
259 if (mRanker != null) {
260 try {
261 int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet())
262 .indexOf(componentName);
Kang Li78c6efc2017-07-13 16:00:42 -0700263 if (selectedPos >= 0 && mTargets != null) {
264 final float selectedProbability = getScore(componentName);
265 int order = 0;
266 for (ResolverTarget target : mTargets) {
267 if (target.getSelectProbability() > selectedProbability) {
268 order++;
269 }
270 }
271 logMetrics(order);
Kang Libbced1c2017-04-05 12:30:55 -0700272 mRanker.train(mTargets, selectedPos);
273 } else {
274 if (DEBUG) {
275 Log.d(TAG, "Selected a unknown component: " + componentName);
276 }
277 }
278 } catch (RemoteException e) {
279 Log.e(TAG, "Error in Train: " + e);
280 }
281 } else {
282 if (DEBUG) {
283 Log.d(TAG, "Ranker is null; skip updateModel.");
284 }
Kang Lia2c7774d2016-12-20 09:39:34 -0800285 }
286 }
Kang Lia2c7774d2016-12-20 09:39:34 -0800287 }
288
Kang Libbced1c2017-04-05 12:30:55 -0700289 // unbind the service and clear unhandled messges.
George Hodulik30f0c6f2019-03-20 18:23:23 -0700290 @Override
Kang Libbced1c2017-04-05 12:30:55 -0700291 public void destroy() {
George Hodulik1f5d9bf2019-04-29 14:55:48 -0700292 mHandler.removeMessages(RANKER_SERVICE_RESULT);
293 mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
Kang Libbced1c2017-04-05 12:30:55 -0700294 if (mConnection != null) {
295 mContext.unbindService(mConnection);
296 mConnection.destroy();
Kang Lic88749f2017-04-05 16:13:12 +0000297 }
George Hodulikc681ce42019-04-12 17:10:31 -0700298 afterCompute();
Kang Libbced1c2017-04-05 12:30:55 -0700299 if (DEBUG) {
300 Log.d(TAG, "Unbinded Resolver Ranker.");
Kang Lic88749f2017-04-05 16:13:12 +0000301 }
Kang Libbced1c2017-04-05 12:30:55 -0700302 }
Kang Lic88749f2017-04-05 16:13:12 +0000303
Kang Li2c571892017-07-05 14:47:32 -0700304 // records metrics for evaluation.
305 private void logMetrics(int selectedPos) {
306 if (mRankerServiceName != null) {
307 MetricsLogger metricsLogger = new MetricsLogger();
308 LogMaker log = new LogMaker(MetricsEvent.ACTION_TARGET_SELECTED);
309 log.setComponentName(mRankerServiceName);
310 int isCategoryUsed = (mAnnotations == null) ? 0 : 1;
311 log.addTaggedData(MetricsEvent.FIELD_IS_CATEGORY_USED, isCategoryUsed);
312 log.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION, selectedPos);
313 metricsLogger.write(log);
314 }
315 }
316
Kang Libbced1c2017-04-05 12:30:55 -0700317 // connect to a ranking service.
George Hodulikccb0cbc2019-05-02 12:23:44 -0700318 private void initRanker(Context context) {
Kang Libbced1c2017-04-05 12:30:55 -0700319 synchronized (mLock) {
320 if (mConnection != null && mRanker != null) {
321 if (DEBUG) {
322 Log.d(TAG, "Ranker still exists; reusing the existing one.");
323 }
Kang Lia2c7774d2016-12-20 09:39:34 -0800324 return;
325 }
Kang Libbced1c2017-04-05 12:30:55 -0700326 }
327 Intent intent = resolveRankerService();
328 if (intent == null) {
329 return;
330 }
331 mConnectSignal = new CountDownLatch(1);
332 mConnection = new ResolverRankerServiceConnection(mConnectSignal);
333 context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
334 }
335
336 // resolve the service for ranking.
337 private Intent resolveRankerService() {
338 Intent intent = new Intent(ResolverRankerService.SERVICE_INTERFACE);
339 final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(intent, 0);
340 for (ResolveInfo resolveInfo : resolveInfos) {
341 if (resolveInfo == null || resolveInfo.serviceInfo == null
342 || resolveInfo.serviceInfo.applicationInfo == null) {
343 if (DEBUG) {
344 Log.d(TAG, "Failed to retrieve a ranker: " + resolveInfo);
345 }
346 continue;
347 }
348 ComponentName componentName = new ComponentName(
349 resolveInfo.serviceInfo.applicationInfo.packageName,
350 resolveInfo.serviceInfo.name);
351 try {
352 final String perm = mPm.getServiceInfo(componentName, 0).permission;
353 if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) {
354 Log.w(TAG, "ResolverRankerService " + componentName + " does not require"
355 + " permission " + ResolverRankerService.BIND_PERMISSION
George Hodulik30f0c6f2019-03-20 18:23:23 -0700356 + " - this service will not be queried for "
357 + "ResolverRankerServiceResolverComparator. add android:permission=\""
Kang Libbced1c2017-04-05 12:30:55 -0700358 + ResolverRankerService.BIND_PERMISSION + "\""
359 + " to the <service> tag for " + componentName
360 + " in the manifest.");
361 continue;
362 }
Kang Li61cf4d12017-04-13 09:17:07 -0700363 if (PackageManager.PERMISSION_GRANTED != mPm.checkPermission(
364 ResolverRankerService.HOLD_PERMISSION,
365 resolveInfo.serviceInfo.packageName)) {
366 Log.w(TAG, "ResolverRankerService " + componentName + " does not hold"
367 + " permission " + ResolverRankerService.HOLD_PERMISSION
George Hodulik30f0c6f2019-03-20 18:23:23 -0700368 + " - this service will not be queried for "
369 + "ResolverRankerServiceResolverComparator.");
Kang Li61cf4d12017-04-13 09:17:07 -0700370 continue;
371 }
Kang Libbced1c2017-04-05 12:30:55 -0700372 } catch (NameNotFoundException e) {
373 Log.e(TAG, "Could not look up service " + componentName
374 + "; component name not found");
375 continue;
Kang Lia2c7774d2016-12-20 09:39:34 -0800376 }
377 if (DEBUG) {
Kang Libbced1c2017-04-05 12:30:55 -0700378 Log.d(TAG, "Succeeded to retrieve a ranker: " + componentName);
Kang Lia2c7774d2016-12-20 09:39:34 -0800379 }
Kang Li2c571892017-07-05 14:47:32 -0700380 mResolvedRankerName = componentName;
Kang Libbced1c2017-04-05 12:30:55 -0700381 intent.setComponent(componentName);
382 return intent;
383 }
384 return null;
385 }
386
Kang Libbced1c2017-04-05 12:30:55 -0700387 private class ResolverRankerServiceConnection implements ServiceConnection {
388 private final CountDownLatch mConnectSignal;
389
390 public ResolverRankerServiceConnection(CountDownLatch connectSignal) {
391 mConnectSignal = connectSignal;
Kang Lia2c7774d2016-12-20 09:39:34 -0800392 }
393
Kang Libbced1c2017-04-05 12:30:55 -0700394 public final IResolverRankerResult resolverRankerResult =
395 new IResolverRankerResult.Stub() {
396 @Override
397 public void sendResult(List<ResolverTarget> targets) throws RemoteException {
398 if (DEBUG) {
399 Log.d(TAG, "Sending Result back to Resolver: " + targets);
400 }
401 synchronized (mLock) {
402 final Message msg = Message.obtain();
George Hodulik1f5d9bf2019-04-29 14:55:48 -0700403 msg.what = RANKER_SERVICE_RESULT;
Kang Libbced1c2017-04-05 12:30:55 -0700404 msg.obj = targets;
405 mHandler.sendMessage(msg);
406 }
Kang Lia2c7774d2016-12-20 09:39:34 -0800407 }
Kang Libbced1c2017-04-05 12:30:55 -0700408 };
Kang Lia2c7774d2016-12-20 09:39:34 -0800409
Kang Libbced1c2017-04-05 12:30:55 -0700410 @Override
411 public void onServiceConnected(ComponentName name, IBinder service) {
Kang Lia2c7774d2016-12-20 09:39:34 -0800412 if (DEBUG) {
Kang Libbced1c2017-04-05 12:30:55 -0700413 Log.d(TAG, "onServiceConnected: " + name);
Kang Lia2c7774d2016-12-20 09:39:34 -0800414 }
Kang Libbced1c2017-04-05 12:30:55 -0700415 synchronized (mLock) {
416 mRanker = IResolverRankerService.Stub.asInterface(service);
417 mConnectSignal.countDown();
418 }
Kang Lia2c7774d2016-12-20 09:39:34 -0800419 }
Kang Li9988f362017-01-18 13:24:06 -0800420
Kang Libbced1c2017-04-05 12:30:55 -0700421 @Override
422 public void onServiceDisconnected(ComponentName name) {
423 if (DEBUG) {
424 Log.d(TAG, "onServiceDisconnected: " + name);
425 }
426 synchronized (mLock) {
427 destroy();
Kang Li9988f362017-01-18 13:24:06 -0800428 }
429 }
Kang Libbced1c2017-04-05 12:30:55 -0700430
431 public void destroy() {
432 synchronized (mLock) {
433 mRanker = null;
434 }
435 }
436 }
437
George Hodulik1f5d9bf2019-04-29 14:55:48 -0700438 @Override
439 void beforeCompute() {
440 super.beforeCompute();
Kang Libbced1c2017-04-05 12:30:55 -0700441 mTargetsDict.clear();
442 mTargets = null;
Kang Li2c571892017-07-05 14:47:32 -0700443 mRankerServiceName = new ComponentName(mContext, this.getClass());
444 mResolvedRankerName = null;
Kang Libbced1c2017-04-05 12:30:55 -0700445 initRanker(mContext);
446 }
447
448 // predict select probabilities if ranking service is valid.
449 private void predictSelectProbabilities(List<ResolverTarget> targets) {
450 if (mConnection == null) {
451 if (DEBUG) {
452 Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction");
453 }
Kang Libbced1c2017-04-05 12:30:55 -0700454 } else {
455 try {
456 mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
457 synchronized (mLock) {
458 if (mRanker != null) {
459 mRanker.predict(targets, mConnection.resolverRankerResult);
460 return;
461 } else {
462 if (DEBUG) {
463 Log.d(TAG, "Ranker has not been initialized; skip predict.");
464 }
465 }
466 }
467 } catch (InterruptedException e) {
468 Log.e(TAG, "Error in Wait for Service Connection.");
469 } catch (RemoteException e) {
470 Log.e(TAG, "Error in Predict: " + e);
471 }
472 }
George Hodulikc681ce42019-04-12 17:10:31 -0700473 afterCompute();
Kang Libbced1c2017-04-05 12:30:55 -0700474 }
475
476 // adds select prob as the default values, according to a pre-trained Logistic Regression model.
477 private void addDefaultSelectProbability(ResolverTarget target) {
478 float sum = 2.5543f * target.getLaunchScore() + 2.8412f * target.getTimeSpentScore() +
479 0.269f * target.getRecencyScore() + 4.2222f * target.getChooserScore();
480 target.setSelectProbability((float) (1.0 / (1.0 + Math.exp(1.6568f - sum))));
481 }
482
483 // sets features for each target
484 private void setFeatures(ResolverTarget target, float recencyScore, float launchScore,
485 float timeSpentScore, float chooserScore) {
486 target.setRecencyScore(recencyScore);
487 target.setLaunchScore(launchScore);
488 target.setTimeSpentScore(timeSpentScore);
489 target.setChooserScore(chooserScore);
490 }
491
492 static boolean isPersistentProcess(ResolvedComponentInfo rci) {
493 if (rci != null && rci.getCount() > 0) {
494 return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
495 ApplicationInfo.FLAG_PERSISTENT) != 0;
496 }
497 return false;
Adam Powelld25267c2015-06-05 18:02:21 -0700498 }
499}