Revert "Add a service to rank apps for ResolverActivity."
This reverts commit 90370e0b2497deba9382ab7ff1539b6849df8139.
b: 36952725
Change-Id: Ifa8f182c707cdbbc989b1f61630f7a8fa856d32d
diff --git a/Android.mk b/Android.mk
index eea465f..634272b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -320,8 +320,6 @@
core/java/android/service/wallpaper/IWallpaperService.aidl \
core/java/android/service/chooser/IChooserTargetService.aidl \
core/java/android/service/chooser/IChooserTargetResult.aidl \
- core/java/android/service/resolver/IResolverRankerService.aidl \
- core/java/android/service/resolver/IResolverRankerResult.aidl \
core/java/android/text/ITextClassificationService.aidl \
core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
@@ -731,7 +729,6 @@
frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \
frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
- frameworks/base/core/java/android/service/resolver/ResolverTarget.aidl \
frameworks/base/core/java/android/speech/tts/Voice.aidl \
frameworks/base/core/java/android/app/usage/CacheQuotaHint.aidl \
frameworks/base/core/java/android/app/usage/ExternalStorageStats.aidl \
diff --git a/api/system-current.txt b/api/system-current.txt
index db2ac19..73cf776 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -53,7 +53,6 @@
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
- field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
@@ -40460,36 +40459,6 @@
}
-package android.service.resolver {
-
- public abstract class ResolverRankerService extends android.app.Service {
- ctor public ResolverRankerService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public void onPredictSharingProbabilities(java.util.List<android.service.resolver.ResolverTarget>);
- method public void onTrainRankingModel(java.util.List<android.service.resolver.ResolverTarget>, int);
- field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
- }
-
- public final class ResolverTarget implements android.os.Parcelable {
- ctor public ResolverTarget();
- method public int describeContents();
- method public float getChooserScore();
- method public float getLaunchScore();
- method public float getRecencyScore();
- method public float getSelectProbability();
- method public float getTimeSpentScore();
- method public void setChooserScore(float);
- method public void setLaunchScore(float);
- method public void setRecencyScore(float);
- method public void setSelectProbability(float);
- method public void setTimeSpentScore(float);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.service.resolver.ResolverTarget> CREATOR;
- }
-
-}
-
package android.service.restrictions {
public abstract class RestrictionsReceiver extends android.content.BroadcastReceiver {
diff --git a/core/java/android/service/resolver/IResolverRankerResult.aidl b/core/java/android/service/resolver/IResolverRankerResult.aidl
deleted file mode 100644
index bda3154..0000000
--- a/core/java/android/service/resolver/IResolverRankerResult.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 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.resolver;
-
-import android.service.resolver.ResolverTarget;
-
-/**
- * @hide
- */
-oneway interface IResolverRankerResult
-{
- void sendResult(in List<ResolverTarget> results);
-}
\ No newline at end of file
diff --git a/core/java/android/service/resolver/IResolverRankerService.aidl b/core/java/android/service/resolver/IResolverRankerService.aidl
deleted file mode 100644
index f0d747d..0000000
--- a/core/java/android/service/resolver/IResolverRankerService.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 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.resolver;
-
-import android.service.resolver.IResolverRankerResult;
-import android.service.resolver.ResolverTarget;
-
-/**
- * @hide
- */
-oneway interface IResolverRankerService
-{
- void predict(in List<ResolverTarget> targets, IResolverRankerResult result);
- void train(in List<ResolverTarget> targets, int selectedPosition);
-}
\ No newline at end of file
diff --git a/core/java/android/service/resolver/ResolverRankerService.java b/core/java/android/service/resolver/ResolverRankerService.java
deleted file mode 100644
index 0506747..0000000
--- a/core/java/android/service/resolver/ResolverRankerService.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2017 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.resolver;
-
-import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.RemoteException;
-import android.service.resolver.ResolverTarget;
-import android.util.Log;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * A service to rank apps according to usage stats of apps, when the system is resolving targets for
- * an Intent.
- *
- * <p>To extend this class, you must declare the service in your manifest file with the
- * {@link android.Manifest.permission#BIND_RESOLVER_RANKER_SERVICE} permission, and include an
- * intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
- * <pre>
- * <service android:name=".MyResolverRankerService"
- * android:exported="true"
- * android:priority="100"
- * android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE">
- * <intent-filter>
- * <action android:name="android.service.resolver.ResolverRankerService" />
- * </intent-filter>
- * </service>
- * </pre>
- * @hide
- */
-@SystemApi
-public abstract class ResolverRankerService extends Service {
-
- private static final String TAG = "ResolverRankerService";
-
- private static final boolean DEBUG = false;
-
- /**
- * The Intent action that a service must respond to. Add it to the intent filter of the service
- * in its manifest.
- */
- @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
-
- /**
- * The permission that a service must require to ensure that only Android system can bind to it.
- * If this permission is not enforced in the AndroidManifest of the service, the system will
- * skip that service.
- */
- public static final String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
-
- private ResolverRankerServiceWrapper mWrapper = null;
-
- /**
- * Called by the system to retrieve a list of probabilities to rank apps/options. To implement
- * it, set selectProbability of each input {@link ResolverTarget}. The higher the
- * selectProbability is, the more likely the {@link ResolverTarget} will be selected by the
- * user. Override this function to provide prediction results.
- *
- * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked.
- *
- * @throws Exception when the prediction task fails.
- */
- public void onPredictSharingProbabilities(final List<ResolverTarget> targets) {}
-
- /**
- * Called by the system to train/update a ranking service, after the user makes a selection from
- * the ranked list of apps. Override this function to enable model updates.
- *
- * @param targets a list of {@link ResolverTarget}, for the list of apps to be ranked.
- * @param selectedPosition the position of the selected app in the list.
- *
- * @throws Exception when the training task fails.
- */
- public void onTrainRankingModel(
- final List<ResolverTarget> targets, final int selectedPosition) {}
-
- private static final String HANDLER_THREAD_NAME = "RESOLVER_RANKER_SERVICE";
- private volatile Handler mHandler;
- private HandlerThread mHandlerThread;
-
- @Override
- public IBinder onBind(Intent intent) {
- if (DEBUG) Log.d(TAG, "onBind " + intent);
- if (!SERVICE_INTERFACE.equals(intent.getAction())) {
- if (DEBUG) Log.d(TAG, "bad intent action " + intent.getAction() + "; returning null");
- return null;
- }
- if (mHandlerThread == null) {
- mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- }
- if (mWrapper == null) {
- mWrapper = new ResolverRankerServiceWrapper();
- }
- return mWrapper;
- }
-
- @Override
- public void onDestroy() {
- mHandler = null;
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
- super.onDestroy();
- }
-
- private static void sendResult(List<ResolverTarget> targets, IResolverRankerResult result) {
- try {
- result.sendResult(targets);
- } catch (Exception e) {
- Log.e(TAG, "failed to send results: " + e);
- }
- }
-
- private class ResolverRankerServiceWrapper extends IResolverRankerService.Stub {
-
- @Override
- public void predict(final List<ResolverTarget> targets, final IResolverRankerResult result)
- throws RemoteException {
- Runnable predictRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- if (DEBUG) {
- Log.d(TAG, "predict calls onPredictSharingProbabilities.");
- }
- onPredictSharingProbabilities(targets);
- sendResult(targets, result);
- } catch (Exception e) {
- Log.e(TAG, "onPredictSharingProbabilities failed; send null results: " + e);
- sendResult(null, result);
- }
- }
- };
- final Handler h = mHandler;
- if (h != null) {
- h.post(predictRunnable);
- }
- }
-
- @Override
- public void train(final List<ResolverTarget> targets, final int selectedPosition)
- throws RemoteException {
- Runnable trainRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- if (DEBUG) {
- Log.d(TAG, "train calls onTranRankingModel");
- }
- onTrainRankingModel(targets, selectedPosition);
- } catch (Exception e) {
- Log.e(TAG, "onTrainRankingModel failed; skip train: " + e);
- }
- }
- };
- final Handler h = mHandler;
- if (h != null) {
- h.post(trainRunnable);
- }
- }
- }
-}
diff --git a/core/java/android/service/resolver/ResolverTarget.aidl b/core/java/android/service/resolver/ResolverTarget.aidl
deleted file mode 100644
index 6cab2d4..0000000
--- a/core/java/android/service/resolver/ResolverTarget.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2017 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.resolver;
-
-/**
- * @hide
- */
-parcelable ResolverTarget;
diff --git a/core/java/android/service/resolver/ResolverTarget.java b/core/java/android/service/resolver/ResolverTarget.java
deleted file mode 100644
index fb3e2d7..0000000
--- a/core/java/android/service/resolver/ResolverTarget.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2017 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.resolver;
-
-import android.annotation.SystemApi;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArrayMap;
-
-import java.util.Map;
-
-/**
- * A ResolverTarget contains features by which an app or option will be ranked, in
- * {@link ResolverRankerService}.
- * @hide
- */
-@SystemApi
-public final class ResolverTarget implements Parcelable {
- private static final String TAG = "ResolverTarget";
-
- /**
- * a float score for recency of last use.
- */
- private float mRecencyScore;
-
- /**
- * a float score for total time spent.
- */
- private float mTimeSpentScore;
-
- /**
- * a float score for number of launches.
- */
- private float mLaunchScore;
-
- /**
- * a float score for number of selected.
- */
- private float mChooserScore;
-
- /**
- * a float score for the probability to be selected.
- */
- private float mSelectProbability;
-
- // constructor for the class.
- public ResolverTarget() {}
-
- ResolverTarget(Parcel in) {
- mRecencyScore = in.readFloat();
- mTimeSpentScore = in.readFloat();
- mLaunchScore = in.readFloat();
- mChooserScore = in.readFloat();
- mSelectProbability = in.readFloat();
- }
-
- /**
- * Gets the score for how recently the target was used in the foreground.
- *
- * @return a float score whose range is [0, 1]. The higher the score is, the more recently the
- * target was used.
- */
- public float getRecencyScore() {
- return mRecencyScore;
- }
-
- /**
- * Sets the score for how recently the target was used in the foreground.
- *
- * @param recencyScore a float score whose range is [0, 1]. The higher the score is, the more
- * recently the target was used.
- */
- public void setRecencyScore(float recencyScore) {
- this.mRecencyScore = recencyScore;
- }
-
- /**
- * Gets the score for how long the target has been used in the foreground.
- *
- * @return a float score whose range is [0, 1]. The higher the score is, the longer the target
- * has been used for.
- */
- public float getTimeSpentScore() {
- return mTimeSpentScore;
- }
-
- /**
- * Sets the score for how long the target has been used in the foreground.
- *
- * @param timeSpentScore a float score whose range is [0, 1]. The higher the score is, the
- * longer the target has been used for.
- */
- public void setTimeSpentScore(float timeSpentScore) {
- this.mTimeSpentScore = timeSpentScore;
- }
-
- /**
- * Gets the score for how many times the target has been launched to the foreground.
- *
- * @return a float score whose range is [0, 1]. The higher the score is, the more times the
- * target has been launched.
- */
- public float getLaunchScore() {
- return mLaunchScore;
- }
-
- /**
- * Sets the score for how many times the target has been launched to the foreground.
- *
- * @param launchScore a float score whose range is [0, 1]. The higher the score is, the more
- * times the target has been launched.
- */
- public void setLaunchScore(float launchScore) {
- this.mLaunchScore = launchScore;
- }
-
- /**
- * Gets the score for how many times the target has been selected by the user to share the same
- * types of content.
- *
- * @return a float score whose range is [0, 1]. The higher the score is, the
- * more times the target has been selected by the user to share the same types of content for.
- */
- public float getChooserScore() {
- return mChooserScore;
- }
-
- /**
- * Sets the score for how many times the target has been selected by the user to share the same
- * types of content.
- *
- * @param chooserScore a float score whose range is [0, 1]. The higher the score is, the more
- * times the target has been selected by the user to share the same types
- * of content for.
- */
- public void setChooserScore(float chooserScore) {
- this.mChooserScore = chooserScore;
- }
-
- /**
- * Gets the probability of how likely this target will be selected by the user.
- *
- * @return a float score whose range is [0, 1]. The higher the score is, the more likely the
- * user is going to select this target.
- */
- public float getSelectProbability() {
- return mSelectProbability;
- }
-
- /**
- * Sets the probability for how like this target will be selected by the user.
- *
- * @param selectProbability a float score whose range is [0, 1]. The higher the score is, the
- * more likely tht user is going to select this target.
- */
- public void setSelectProbability(float selectProbability) {
- this.mSelectProbability = selectProbability;
- }
-
- // serialize the class to a string.
- @Override
- public String toString() {
- return "ResolverTarget{"
- + mRecencyScore + ", "
- + mTimeSpentScore + ", "
- + mLaunchScore + ", "
- + mChooserScore + ", "
- + mSelectProbability + "}";
- }
-
- // describes the kinds of special objects contained in this Parcelable instance's marshaled
- // representation.
- @Override
- public int describeContents() {
- return 0;
- }
-
- // flattens this object in to a Parcel.
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeFloat(mRecencyScore);
- dest.writeFloat(mTimeSpentScore);
- dest.writeFloat(mLaunchScore);
- dest.writeFloat(mChooserScore);
- dest.writeFloat(mSelectProbability);
- }
-
- // creator definition for the class.
- public static final Creator<ResolverTarget> CREATOR
- = new Creator<ResolverTarget>() {
- @Override
- public ResolverTarget createFromParcel(Parcel source) {
- return new ResolverTarget(source);
- }
-
- @Override
- public ResolverTarget[] newArray(int size) {
- return new ResolverTarget[size];
- }
- };
-}
diff --git a/core/java/com/android/internal/app/LRResolverRankerService.java b/core/java/com/android/internal/app/LRResolverRankerService.java
deleted file mode 100644
index 1cad7c7..0000000
--- a/core/java/com/android/internal/app/LRResolverRankerService.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2017 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.internal.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Environment;
-import android.os.IBinder;
-import android.os.storage.StorageManager;
-import android.service.resolver.ResolverRankerService;
-import android.service.resolver.ResolverTarget;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A Logistic Regression based {@link android.service.resolver.ResolverRankerService}, to be used
- * in {@link ResolverComparator}.
- */
-public final class LRResolverRankerService extends ResolverRankerService {
- private static final String TAG = "LRResolverRankerService";
-
- private static final boolean DEBUG = false;
-
- private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
- private static final String BIAS_PREF_KEY = "bias";
- private static final String VERSION_PREF_KEY = "version";
-
- private static final String LAUNCH_SCORE = "launch";
- private static final String TIME_SPENT_SCORE = "timeSpent";
- private static final String RECENCY_SCORE = "recency";
- private static final String CHOOSER_SCORE = "chooser";
-
- // parameters for a pre-trained model, to initialize the app ranker. When updating the
- // pre-trained model, please update these params, as well as initModel().
- private static final int CURRENT_VERSION = 1;
- private static final float LEARNING_RATE = 0.0001f;
- private static final float REGULARIZER_PARAM = 0.0001f;
-
- private SharedPreferences mParamSharedPref;
- private ArrayMap<String, Float> mFeatureWeights;
- private float mBias;
-
- @Override
- public IBinder onBind(Intent intent) {
- initModel();
- return super.onBind(intent);
- }
-
- @Override
- public void onPredictSharingProbabilities(List<ResolverTarget> targets) {
- final int size = targets.size();
- for (int i = 0; i < size; ++i) {
- ResolverTarget target = targets.get(i);
- ArrayMap<String, Float> features = getFeatures(target);
- target.setSelectProbability(predict(features));
- }
- }
-
- @Override
- public void onTrainRankingModel(List<ResolverTarget> targets, int selectedPosition) {
- final int size = targets.size();
- if (selectedPosition < 0 || selectedPosition >= size) {
- if (DEBUG) {
- Log.d(TAG, "Invalid Position of Selected App " + selectedPosition);
- }
- return;
- }
- final ArrayMap<String, Float> positive = getFeatures(targets.get(selectedPosition));
- final float positiveProbability = targets.get(selectedPosition).getSelectProbability();
- final int targetSize = targets.size();
- for (int i = 0; i < targetSize; ++i) {
- if (i == selectedPosition) {
- continue;
- }
- final ArrayMap<String, Float> negative = getFeatures(targets.get(i));
- final float negativeProbability = targets.get(i).getSelectProbability();
- if (negativeProbability > positiveProbability) {
- update(negative, negativeProbability, false);
- update(positive, positiveProbability, true);
- }
- }
- commitUpdate();
- }
-
- private void initModel() {
- mParamSharedPref = getParamSharedPref();
- mFeatureWeights = new ArrayMap<>(4);
- if (mParamSharedPref == null ||
- mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
- // Initializing the app ranker to a pre-trained model. When updating the pre-trained
- // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
- // REGULARIZER_PARAM.
- mBias = -1.6568f;
- mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
- mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
- mFeatureWeights.put(RECENCY_SCORE, 0.269f);
- mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
- } else {
- mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
- mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
- mFeatureWeights.put(
- TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
- mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
- mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
- }
- }
-
- private ArrayMap<String, Float> getFeatures(ResolverTarget target) {
- ArrayMap<String, Float> features = new ArrayMap<>(4);
- features.put(RECENCY_SCORE, target.getRecencyScore());
- features.put(TIME_SPENT_SCORE, target.getTimeSpentScore());
- features.put(LAUNCH_SCORE, target.getLaunchScore());
- features.put(CHOOSER_SCORE, target.getChooserScore());
- return features;
- }
-
- private float predict(ArrayMap<String, Float> target) {
- if (target == null) {
- return 0.0f;
- }
- final int featureSize = target.size();
- float sum = 0.0f;
- for (int i = 0; i < featureSize; i++) {
- String featureName = target.keyAt(i);
- float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
- sum += weight * target.valueAt(i);
- }
- return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
- }
-
- private void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
- if (target == null) {
- return;
- }
- final int featureSize = target.size();
- float error = isSelected ? 1.0f - predict : -predict;
- for (int i = 0; i < featureSize; i++) {
- String featureName = target.keyAt(i);
- float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
- mBias += LEARNING_RATE * error;
- currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
- LEARNING_RATE * error * target.valueAt(i);
- mFeatureWeights.put(featureName, currentWeight);
- }
- if (DEBUG) {
- Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
- }
- }
-
- private void commitUpdate() {
- try {
- SharedPreferences.Editor editor = mParamSharedPref.edit();
- editor.putFloat(BIAS_PREF_KEY, mBias);
- final int size = mFeatureWeights.size();
- for (int i = 0; i < size; i++) {
- editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
- }
- editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
- editor.apply();
- } catch (Exception e) {
- Log.e(TAG, "Failed to commit update" + e);
- }
- }
-
- private SharedPreferences getParamSharedPref() {
- // The package info in the context isn't initialized in the way it is for normal apps,
- // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
- // build the path manually below using the same policy that appears in ContextImpl.
- if (DEBUG) {
- Log.d(TAG, "Context Package Name: " + getPackageName());
- }
- final File prefsFile = new File(new File(
- Environment.getDataUserCePackageDirectory(
- StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
- "shared_prefs"),
- PARAM_SHARED_PREF_NAME + ".xml");
- return getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
- }
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 622b708..3f1c9ad 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -530,9 +530,6 @@
getMainThreadHandler().removeCallbacks(mPostListReadyRunnable);
mPostListReadyRunnable = null;
}
- if (mAdapter != null && mAdapter.mResolverListController != null) {
- mAdapter.mResolverListController.destroy();
- }
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 73b62a5..096fcb8 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -26,34 +26,20 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.SharedPreferences;
-import android.content.ServiceConnection;
import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
import android.os.storage.StorageManager;
import android.os.UserHandle;
-import android.service.resolver.IResolverRankerService;
-import android.service.resolver.IResolverRankerResult;
-import android.service.resolver.ResolverRankerService;
-import android.service.resolver.ResolverTarget;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import java.io.File;
-import java.lang.InterruptedException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -75,15 +61,11 @@
private static final float RECENCY_MULTIPLIER = 2.f;
- // message types
- private static final int RESOLVER_RANKER_SERVICE_RESULT = 0;
- private static final int RESOLVER_RANKER_RESULT_TIMEOUT = 1;
-
- // timeout for establishing connections with a ResolverRankerService.
- private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200;
- // timeout for establishing connections with a ResolverRankerService, collecting features and
- // predicting ranking scores.
- private static final int WATCHDOG_TIMEOUT_MILLIS = 500;
+ // feature names used in ranking.
+ private static final String LAUNCH_SCORE = "launch";
+ private static final String TIME_SPENT_SCORE = "timeSpent";
+ private static final String RECENCY_SCORE = "recency";
+ private static final String CHOOSER_SCORE = "chooser";
private final Collator mCollator;
private final boolean mHttp;
@@ -92,74 +74,18 @@
private final Map<String, UsageStats> mStats;
private final long mCurrentTime;
private final long mSinceTime;
- private final LinkedHashMap<ComponentName, ResolverTarget> mTargetsDict = new LinkedHashMap<>();
+ private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
private final String mReferrerPackage;
- private final Object mLock = new Object();
- private ArrayList<ResolverTarget> mTargets;
private String mContentType;
private String[] mAnnotations;
private String mAction;
- private IResolverRankerService mRanker;
- private ResolverRankerServiceConnection mConnection;
- private AfterCompute mAfterCompute;
- private Context mContext;
- private CountDownLatch mConnectSignal;
+ private LogisticRegressionAppRanker mRanker;
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case RESOLVER_RANKER_SERVICE_RESULT:
- if (DEBUG) {
- Log.d(TAG, "RESOLVER_RANKER_SERVICE_RESULT");
- }
- if (mHandler.hasMessages(RESOLVER_RANKER_RESULT_TIMEOUT)) {
- if (msg.obj != null) {
- final List<ResolverTarget> receivedTargets =
- (List<ResolverTarget>) msg.obj;
- if (receivedTargets != null && mTargets != null
- && receivedTargets.size() == mTargets.size()) {
- final int size = mTargets.size();
- for (int i = 0; i < size; ++i) {
- mTargets.get(i).setSelectProbability(
- receivedTargets.get(i).getSelectProbability());
- }
- } else {
- Log.e(TAG, "Sizes of sent and received ResolverTargets diff.");
- }
- } else {
- Log.e(TAG, "Receiving null prediction results.");
- }
- mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
- mAfterCompute.afterCompute();
- }
- break;
-
- case RESOLVER_RANKER_RESULT_TIMEOUT:
- if (DEBUG) {
- Log.d(TAG, "RESOLVER_RANKER_RESULT_TIMEOUT; unbinding services");
- }
- mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
- mAfterCompute.afterCompute();
- break;
-
- default:
- super.handleMessage(msg);
- }
- }
- };
-
- public interface AfterCompute {
- public void afterCompute ();
- }
-
- public ResolverComparator(Context context, Intent intent, String referrerPackage,
- AfterCompute afterCompute) {
+ public ResolverComparator(Context context, Intent intent, String referrerPackage) {
mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
String scheme = intent.getScheme();
mHttp = "http".equals(scheme) || "https".equals(scheme);
mReferrerPackage = referrerPackage;
- mAfterCompute = afterCompute;
- mContext = context;
mPm = context.getPackageManager();
mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
@@ -170,9 +96,9 @@
mContentType = intent.getType();
getContentAnnotations(intent);
mAction = intent.getAction();
+ mRanker = new LogisticRegressionAppRanker(context);
}
- // get annotations of content from intent.
public void getContentAnnotations(Intent intent) {
ArrayList<String> annotations = intent.getStringArrayListExtra(
Intent.EXTRA_CONTENT_ANNOTATIONS);
@@ -188,24 +114,20 @@
}
}
- public void setCallBack(AfterCompute afterCompute) {
- mAfterCompute = afterCompute;
- }
-
- // compute features for each target according to usage stats of targets.
public void compute(List<ResolvedComponentInfo> targets) {
- reset();
+ mScoredTargets.clear();
final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
- float mostRecencyScore = 1.0f;
- float mostTimeSpentScore = 1.0f;
- float mostLaunchScore = 1.0f;
- float mostChooserScore = 1.0f;
+ long mostRecentlyUsedTime = recentSinceTime + 1;
+ long mostTimeSpent = 1;
+ int mostLaunched = 1;
+ int mostSelected = 1;
for (ResolvedComponentInfo target : targets) {
- final ResolverTarget resolverTarget = new ResolverTarget();
- mTargetsDict.put(target.name, resolverTarget);
+ final ScoredTarget scoredTarget
+ = new ScoredTarget(target.getResolveInfoAt(0).activityInfo);
+ mScoredTargets.put(target.name, scoredTarget);
final UsageStats pkStats = mStats.get(target.name.getPackageName());
if (pkStats != null) {
// Only count recency for apps that weren't the caller
@@ -213,33 +135,31 @@
// Persistent processes muck this up, so omit them too.
if (!target.name.getPackageName().equals(mReferrerPackage)
&& !isPersistentProcess(target)) {
- final float recencyScore =
- (float) Math.max(pkStats.getLastTimeUsed() - recentSinceTime, 0);
- resolverTarget.setRecencyScore(recencyScore);
- if (recencyScore > mostRecencyScore) {
- mostRecencyScore = recencyScore;
+ final long lastTimeUsed = pkStats.getLastTimeUsed();
+ scoredTarget.lastTimeUsed = lastTimeUsed;
+ if (lastTimeUsed > mostRecentlyUsedTime) {
+ mostRecentlyUsedTime = lastTimeUsed;
}
}
- final float timeSpentScore = (float) pkStats.getTotalTimeInForeground();
- resolverTarget.setTimeSpentScore(timeSpentScore);
- if (timeSpentScore > mostTimeSpentScore) {
- mostTimeSpentScore = timeSpentScore;
+ final long timeSpent = pkStats.getTotalTimeInForeground();
+ scoredTarget.timeSpent = timeSpent;
+ if (timeSpent > mostTimeSpent) {
+ mostTimeSpent = timeSpent;
}
- final float launchScore = (float) pkStats.mLaunchCount;
- resolverTarget.setLaunchScore(launchScore);
- if (launchScore > mostLaunchScore) {
- mostLaunchScore = launchScore;
+ final int launched = pkStats.mLaunchCount;
+ scoredTarget.launchCount = launched;
+ if (launched > mostLaunched) {
+ mostLaunched = launched;
}
- float chooserScore = 0.0f;
+ int selected = 0;
if (pkStats.mChooserCounts != null && mAction != null
&& pkStats.mChooserCounts.get(mAction) != null) {
- chooserScore = (float) pkStats.mChooserCounts.get(mAction)
- .getOrDefault(mContentType, 0);
+ selected = pkStats.mChooserCounts.get(mAction).getOrDefault(mContentType, 0);
if (mAnnotations != null) {
final int size = mAnnotations.length;
for (int i = 0; i < size; i++) {
- chooserScore += (float) pkStats.mChooserCounts.get(mAction)
+ selected += pkStats.mChooserCounts.get(mAction)
.getOrDefault(mAnnotations[i], 0);
}
}
@@ -249,37 +169,44 @@
Log.d(TAG, "Action type is null");
} else {
Log.d(TAG, "Chooser Count of " + mAction + ":" +
- target.name.getPackageName() + " is " +
- Float.toString(chooserScore));
+ target.name.getPackageName() + " is " + Integer.toString(selected));
}
}
- resolverTarget.setChooserScore(chooserScore);
- if (chooserScore > mostChooserScore) {
- mostChooserScore = chooserScore;
+ scoredTarget.chooserCount = selected;
+ if (selected > mostSelected) {
+ mostSelected = selected;
}
}
}
+
if (DEBUG) {
- Log.d(TAG, "compute - mostRecencyScore: " + mostRecencyScore
- + " mostTimeSpentScore: " + mostTimeSpentScore
- + " mostLaunchScore: " + mostLaunchScore
- + " mostChooserScore: " + mostChooserScore);
+ Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime
+ + " mostTimeSpent: " + mostTimeSpent
+ + " recentSinceTime: " + recentSinceTime
+ + " mostLaunched: " + mostLaunched);
}
- mTargets = new ArrayList<>(mTargetsDict.values());
- for (ResolverTarget target : mTargets) {
- final float recency = target.getRecencyScore() / mostRecencyScore;
- setFeatures(target, recency * recency * RECENCY_MULTIPLIER,
- target.getLaunchScore() / mostLaunchScore,
- target.getTimeSpentScore() / mostTimeSpentScore,
- target.getChooserScore() / mostChooserScore);
- addDefaultSelectProbability(target);
+ for (ScoredTarget target : mScoredTargets.values()) {
+ final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0)
+ / (mostRecentlyUsedTime - recentSinceTime);
+ target.setFeatures((float) target.launchCount / mostLaunched,
+ (float) target.timeSpent / mostTimeSpent,
+ recency * recency * RECENCY_MULTIPLIER,
+ (float) target.chooserCount / mostSelected);
+ target.selectProb = mRanker.predict(target.getFeatures());
if (DEBUG) {
Log.d(TAG, "Scores: " + target);
}
}
- predictSelectProbabilities(mTargets);
+ }
+
+ static boolean isPersistentProcess(ResolvedComponentInfo rci) {
+ if (rci != null && rci.getCount() > 0) {
+ return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
+ ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+ return false;
}
@Override
@@ -318,16 +245,16 @@
// Pinned items stay stable within a normal lexical sort and ignore scoring.
if (!lPinned && !rPinned) {
if (mStats != null) {
- final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
+ final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName(
lhs.activityInfo.packageName, lhs.activityInfo.name));
- final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
+ final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
rhs.activityInfo.packageName, rhs.activityInfo.name));
- final int selectProbabilityDiff = Float.compare(
- rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
+ final int selectProbDiff = Float.compare(
+ rhsTarget.selectProb, lhsTarget.selectProb);
- if (selectProbabilityDiff != 0) {
- return selectProbabilityDiff > 0 ? 1 : -1;
+ if (selectProbDiff != 0) {
+ return selectProbDiff > 0 ? 1 : -1;
}
}
}
@@ -341,234 +268,177 @@
}
public float getScore(ComponentName name) {
- final ResolverTarget target = mTargetsDict.get(name);
+ final ScoredTarget target = mScoredTargets.get(name);
if (target != null) {
- return target.getSelectProbability();
+ return target.selectProb;
}
return 0;
}
+ static class ScoredTarget {
+ public final ComponentInfo componentInfo;
+ public long lastTimeUsed;
+ public long timeSpent;
+ public long launchCount;
+ public long chooserCount;
+ public ArrayMap<String, Float> features;
+ public float selectProb;
+
+ public ScoredTarget(ComponentInfo ci) {
+ componentInfo = ci;
+ features = new ArrayMap<>(5);
+ }
+
+ @Override
+ public String toString() {
+ return "ScoredTarget{" + componentInfo
+ + " lastTimeUsed: " + lastTimeUsed
+ + " timeSpent: " + timeSpent
+ + " launchCount: " + launchCount
+ + " chooserCount: " + chooserCount
+ + " selectProb: " + selectProb
+ + "}";
+ }
+
+ public void setFeatures(float launchCountScore, float usageTimeScore, float recencyScore,
+ float chooserCountScore) {
+ features.put(LAUNCH_SCORE, launchCountScore);
+ features.put(TIME_SPENT_SCORE, usageTimeScore);
+ features.put(RECENCY_SCORE, recencyScore);
+ features.put(CHOOSER_SCORE, chooserCountScore);
+ }
+
+ public ArrayMap<String, Float> getFeatures() {
+ return features;
+ }
+ }
+
public void updateChooserCounts(String packageName, int userId, String action) {
if (mUsm != null) {
mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action);
}
}
- // update ranking model when the connection to it is valid.
public void updateModel(ComponentName componentName) {
- synchronized (mLock) {
- if (mRanker != null) {
- try {
- int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet())
- .indexOf(componentName);
- if (selectedPos > 0) {
- mRanker.train(mTargets, selectedPos);
- } else {
- if (DEBUG) {
- Log.d(TAG, "Selected a unknown component: " + componentName);
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error in Train: " + e);
- }
- } else {
- if (DEBUG) {
- Log.d(TAG, "Ranker is null; skip updateModel.");
- }
+ if (mScoredTargets == null || componentName == null ||
+ !mScoredTargets.containsKey(componentName)) {
+ return;
+ }
+ ScoredTarget selected = mScoredTargets.get(componentName);
+ for (ComponentName targetComponent : mScoredTargets.keySet()) {
+ if (targetComponent.equals(componentName)) {
+ continue;
+ }
+ ScoredTarget target = mScoredTargets.get(targetComponent);
+ // A potential point of optimization. Save updates or derive a closed form for the
+ // positive case, to avoid calculating them repeatedly.
+ if (target.selectProb >= selected.selectProb) {
+ mRanker.update(target.getFeatures(), target.selectProb, false);
+ mRanker.update(selected.getFeatures(), selected.selectProb, true);
}
}
+ mRanker.commitUpdate();
}
- // unbind the service and clear unhandled messges.
- public void destroy() {
- mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
- mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection.destroy();
- }
- if (DEBUG) {
- Log.d(TAG, "Unbinded Resolver Ranker.");
- }
- }
+ class LogisticRegressionAppRanker {
+ private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
+ private static final String BIAS_PREF_KEY = "bias";
+ private static final String VERSION_PREF_KEY = "version";
- // connect to a ranking service.
- private void initRanker(Context context) {
- synchronized (mLock) {
- if (mConnection != null && mRanker != null) {
- if (DEBUG) {
- Log.d(TAG, "Ranker still exists; reusing the existing one.");
- }
+ // parameters for a pre-trained model, to initialize the app ranker. When updating the
+ // pre-trained model, please update these params, as well as initModel().
+ private static final int CURRENT_VERSION = 1;
+ private static final float LEARNING_RATE = 0.0001f;
+ private static final float REGULARIZER_PARAM = 0.0001f;
+
+ private SharedPreferences mParamSharedPref;
+ private ArrayMap<String, Float> mFeatureWeights;
+ private float mBias;
+
+ public LogisticRegressionAppRanker(Context context) {
+ mParamSharedPref = getParamSharedPref(context);
+ initModel();
+ }
+
+ public float predict(ArrayMap<String, Float> target) {
+ if (target == null) {
+ return 0.0f;
+ }
+ final int featureSize = target.size();
+ float sum = 0.0f;
+ for (int i = 0; i < featureSize; i++) {
+ String featureName = target.keyAt(i);
+ float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+ sum += weight * target.valueAt(i);
+ }
+ return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
+ }
+
+ public void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
+ if (target == null) {
return;
}
- }
- Intent intent = resolveRankerService();
- if (intent == null) {
- return;
- }
- mConnectSignal = new CountDownLatch(1);
- mConnection = new ResolverRankerServiceConnection(mConnectSignal);
- context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
- }
-
- // resolve the service for ranking.
- private Intent resolveRankerService() {
- Intent intent = new Intent(ResolverRankerService.SERVICE_INTERFACE);
- final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(intent, 0);
- for (ResolveInfo resolveInfo : resolveInfos) {
- if (resolveInfo == null || resolveInfo.serviceInfo == null
- || resolveInfo.serviceInfo.applicationInfo == null) {
- if (DEBUG) {
- Log.d(TAG, "Failed to retrieve a ranker: " + resolveInfo);
- }
- continue;
- }
- ComponentName componentName = new ComponentName(
- resolveInfo.serviceInfo.applicationInfo.packageName,
- resolveInfo.serviceInfo.name);
- try {
- final String perm = mPm.getServiceInfo(componentName, 0).permission;
- if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) {
- Log.w(TAG, "ResolverRankerService " + componentName + " does not require"
- + " permission " + ResolverRankerService.BIND_PERMISSION
- + " - this service will not be queried for ResolverComparator."
- + " add android:permission=\""
- + ResolverRankerService.BIND_PERMISSION + "\""
- + " to the <service> tag for " + componentName
- + " in the manifest.");
- continue;
- }
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Could not look up service " + componentName
- + "; component name not found");
- continue;
+ final int featureSize = target.size();
+ float error = isSelected ? 1.0f - predict : -predict;
+ for (int i = 0; i < featureSize; i++) {
+ String featureName = target.keyAt(i);
+ float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+ mBias += LEARNING_RATE * error;
+ currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight +
+ LEARNING_RATE * error * target.valueAt(i);
+ mFeatureWeights.put(featureName, currentWeight);
}
if (DEBUG) {
- Log.d(TAG, "Succeeded to retrieve a ranker: " + componentName);
+ Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias);
}
- intent.setComponent(componentName);
- return intent;
- }
- return null;
- }
-
- // set a watchdog, to avoid waiting for ranking service for too long.
- private void startWatchDog(int timeOutLimit) {
- if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + timeOutLimit + "ms");
- if (mHandler == null) {
- Log.d(TAG, "Error: Handler is Null; Needs to be initialized.");
- }
- mHandler.sendEmptyMessageDelayed(RESOLVER_RANKER_RESULT_TIMEOUT, timeOutLimit);
- }
-
- private class ResolverRankerServiceConnection implements ServiceConnection {
- private final CountDownLatch mConnectSignal;
-
- public ResolverRankerServiceConnection(CountDownLatch connectSignal) {
- mConnectSignal = connectSignal;
}
- public final IResolverRankerResult resolverRankerResult =
- new IResolverRankerResult.Stub() {
- @Override
- public void sendResult(List<ResolverTarget> targets) throws RemoteException {
- if (DEBUG) {
- Log.d(TAG, "Sending Result back to Resolver: " + targets);
- }
- synchronized (mLock) {
- final Message msg = Message.obtain();
- msg.what = RESOLVER_RANKER_SERVICE_RESULT;
- msg.obj = targets;
- mHandler.sendMessage(msg);
- }
+ public void commitUpdate() {
+ SharedPreferences.Editor editor = mParamSharedPref.edit();
+ editor.putFloat(BIAS_PREF_KEY, mBias);
+ final int size = mFeatureWeights.size();
+ for (int i = 0; i < size; i++) {
+ editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
}
- };
+ editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
+ editor.apply();
+ }
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
+ private SharedPreferences getParamSharedPref(Context context) {
+ // The package info in the context isn't initialized in the way it is for normal apps,
+ // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
+ // build the path manually below using the same policy that appears in ContextImpl.
if (DEBUG) {
- Log.d(TAG, "onServiceConnected: " + name);
+ Log.d(TAG, "Context Package Name: " + context.getPackageName());
}
- synchronized (mLock) {
- mRanker = IResolverRankerService.Stub.asInterface(service);
- mConnectSignal.countDown();
- }
+ final File prefsFile = new File(new File(
+ Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
+ context.getUserId(), context.getPackageName()),
+ "shared_prefs"),
+ PARAM_SHARED_PREF_NAME + ".xml");
+ return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
}
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) {
- Log.d(TAG, "onServiceDisconnected: " + name);
- }
- synchronized (mLock) {
- destroy();
+ private void initModel() {
+ mFeatureWeights = new ArrayMap<>(4);
+ if (mParamSharedPref == null ||
+ mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
+ // Initializing the app ranker to a pre-trained model. When updating the pre-trained
+ // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
+ // REGULARIZER_PARAM.
+ mBias = -1.6568f;
+ mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
+ mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
+ mFeatureWeights.put(RECENCY_SCORE, 0.269f);
+ mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
+ } else {
+ mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
+ mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
+ mFeatureWeights.put(
+ TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
+ mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
+ mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
}
}
-
- public void destroy() {
- synchronized (mLock) {
- mRanker = null;
- }
- }
- }
-
- private void reset() {
- mTargetsDict.clear();
- mTargets = null;
- startWatchDog(WATCHDOG_TIMEOUT_MILLIS);
- initRanker(mContext);
- }
-
- // predict select probabilities if ranking service is valid.
- private void predictSelectProbabilities(List<ResolverTarget> targets) {
- if (mConnection == null) {
- if (DEBUG) {
- Log.d(TAG, "Has not found valid ResolverRankerService; Skip Prediction");
- }
- return;
- } else {
- try {
- mConnectSignal.await(CONNECTION_COST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- synchronized (mLock) {
- if (mRanker != null) {
- mRanker.predict(targets, mConnection.resolverRankerResult);
- return;
- } else {
- if (DEBUG) {
- Log.d(TAG, "Ranker has not been initialized; skip predict.");
- }
- }
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Error in Wait for Service Connection.");
- } catch (RemoteException e) {
- Log.e(TAG, "Error in Predict: " + e);
- }
- }
- mAfterCompute.afterCompute();
- }
-
- // adds select prob as the default values, according to a pre-trained Logistic Regression model.
- private void addDefaultSelectProbability(ResolverTarget target) {
- float sum = 2.5543f * target.getLaunchScore() + 2.8412f * target.getTimeSpentScore() +
- 0.269f * target.getRecencyScore() + 4.2222f * target.getChooserScore();
- target.setSelectProbability((float) (1.0 / (1.0 + Math.exp(1.6568f - sum))));
- }
-
- // sets features for each target
- private void setFeatures(ResolverTarget target, float recencyScore, float launchScore,
- float timeSpentScore, float chooserScore) {
- target.setRecencyScore(recencyScore);
- target.setLaunchScore(launchScore);
- target.setTimeSpentScore(timeSpentScore);
- target.setChooserScore(chooserScore);
- }
-
- static boolean isPersistentProcess(ResolvedComponentInfo rci) {
- if (rci != null && rci.getCount() > 0) {
- return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
- ApplicationInfo.FLAG_PERSISTENT) != 0;
- }
- return false;
}
}
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index e8bebb7..4071ff4 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -32,10 +32,8 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import java.lang.InterruptedException;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.concurrent.CountDownLatch;
import java.util.List;
/**
@@ -207,42 +205,14 @@
return listToReturn;
}
- private class ComputeCallback implements ResolverComparator.AfterCompute {
-
- private CountDownLatch mFinishComputeSignal;
-
- public ComputeCallback(CountDownLatch finishComputeSignal) {
- mFinishComputeSignal = finishComputeSignal;
- }
-
- public void afterCompute () {
- mFinishComputeSignal.countDown();
- }
- }
-
@VisibleForTesting
@WorkerThread
public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) {
- final CountDownLatch finishComputeSignal = new CountDownLatch(1);
- ComputeCallback callback = new ComputeCallback(finishComputeSignal);
if (mResolverComparator == null) {
- mResolverComparator =
- new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, callback);
- } else {
- mResolverComparator.setCallBack(callback);
+ mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage);
}
- try {
- long beforeRank = System.currentTimeMillis();
- mResolverComparator.compute(inputList);
- finishComputeSignal.await();
- Collections.sort(inputList, mResolverComparator);
- long afterRank = System.currentTimeMillis();
- if (DEBUG) {
- Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Compute & Sort was interrupted: " + e);
- }
+ mResolverComparator.compute(inputList);
+ Collections.sort(inputList, mResolverComparator);
}
private static boolean isSameResolvedComponent(ResolveInfo a,
@@ -263,7 +233,7 @@
@VisibleForTesting
public float getScore(ResolverActivity.DisplayResolveInfo target) {
if (mResolverComparator == null) {
- return 0.0f;
+ mResolverComparator = new ResolverComparator(mContext, mTargetIntent, mReferrerPackage);
}
return mResolverComparator.getScore(target.getResolvedComponentName());
}
@@ -279,10 +249,4 @@
mResolverComparator.updateChooserCounts(packageName, userId, action);
}
}
-
- public void destroy() {
- if (mResolverComparator != null) {
- mResolverComparator.destroy();
- }
- }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index faaca53..ffcb8476 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3129,15 +3129,6 @@
<permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
android:protectionLevel="signature" />
- <!-- @SystemApi Must be required by services that extend
- {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
- bind to them.
- <p>Protection level: signature
- @hide
- -->
- <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
- android:protectionLevel="signature" />
-
<!-- Must be required by a {@link
android.service.notification.ConditionProviderService},
to ensure that only the system can bind to it.
@@ -3643,14 +3634,6 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
- <service android:name="com.android.internal.app.LRResolverRankerService"
- android:permission="android.permission.BIND_RESOLVER_RANKER_SERVICE"
- android:exported="false"
- android:priority="-1" >
- <intent-filter>
- <action android:name="android.service.resolver.ResolverRankerService" />
- </intent-filter>
- </service>
</application>
</manifest>