Merge "Allow exemption of roles/permissions from broadcast response events." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d79cb12422
@@ -280,6 +280,20 @@ public interface AppStandbyInternal {
|
|||||||
*/
|
*/
|
||||||
boolean shouldNoteResponseEventForAllBroadcastSessions();
|
boolean shouldNoteResponseEventForAllBroadcastSessions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of roles whose holders are exempted from the requirement of starting
|
||||||
|
* a response event after receiving a broadcast.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<String> getBroadcastResponseExemptedRoles();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of permissions whose holders are exempted from the requirement of starting
|
||||||
|
* a response event after receiving a broadcast.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<String> getBroadcastResponseExemptedPermissions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the last known value corresponding to the {@code key} from
|
* Return the last known value corresponding to the {@code key} from
|
||||||
* {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
|
* {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ import android.os.UserHandle;
|
|||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings.Global;
|
import android.provider.Settings.Global;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.IndentingPrintWriter;
|
import android.util.IndentingPrintWriter;
|
||||||
@@ -420,6 +421,26 @@ public class AppStandbyController
|
|||||||
volatile boolean mNoteResponseEventForAllBroadcastSessions =
|
volatile boolean mNoteResponseEventForAllBroadcastSessions =
|
||||||
ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS;
|
ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of roles whose holders are exempted from the requirement of starting
|
||||||
|
* a response event after receiving a broadcast.
|
||||||
|
*
|
||||||
|
* The list of roles will be separated by '|' in the string.
|
||||||
|
*/
|
||||||
|
volatile String mBroadcastResponseExemptedRoles =
|
||||||
|
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES;
|
||||||
|
volatile List<String> mBroadcastResponseExemptedRolesList = Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of permissions whose holders are exempted from the requirement of starting
|
||||||
|
* a response event after receiving a broadcast.
|
||||||
|
*
|
||||||
|
* The list of permissions will be separated by '|' in the string.
|
||||||
|
*/
|
||||||
|
volatile String mBroadcastResponseExemptedPermissions =
|
||||||
|
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS;
|
||||||
|
volatile List<String> mBroadcastResponseExemptedPermissionsList = Collections.EMPTY_LIST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
|
* Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
|
||||||
*
|
*
|
||||||
@@ -1959,6 +1980,18 @@ public class AppStandbyController
|
|||||||
return mNoteResponseEventForAllBroadcastSessions;
|
return mNoteResponseEventForAllBroadcastSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public List<String> getBroadcastResponseExemptedRoles() {
|
||||||
|
return mBroadcastResponseExemptedRolesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public List<String> getBroadcastResponseExemptedPermissions() {
|
||||||
|
return mBroadcastResponseExemptedPermissionsList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getAppStandbyConstant(@NonNull String key) {
|
public String getAppStandbyConstant(@NonNull String key) {
|
||||||
@@ -2311,6 +2344,14 @@ public class AppStandbyController
|
|||||||
pw.print(mNoteResponseEventForAllBroadcastSessions);
|
pw.print(mNoteResponseEventForAllBroadcastSessions);
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
|
pw.print(" mBroadcastResponseExemptedRoles");
|
||||||
|
pw.print(mBroadcastResponseExemptedRoles);
|
||||||
|
pw.println();
|
||||||
|
|
||||||
|
pw.print(" mBroadcastResponseExemptedPermissions");
|
||||||
|
pw.print(mBroadcastResponseExemptedPermissions);
|
||||||
|
pw.println();
|
||||||
|
|
||||||
pw.println();
|
pw.println();
|
||||||
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
|
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
|
||||||
pw.print(" mAllowRestrictedBucket=");
|
pw.print(" mAllowRestrictedBucket=");
|
||||||
@@ -2795,6 +2836,10 @@ public class AppStandbyController
|
|||||||
"broadcast_sessions_with_response_duration_ms";
|
"broadcast_sessions_with_response_duration_ms";
|
||||||
private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
|
private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
|
||||||
"note_response_event_for_all_broadcast_sessions";
|
"note_response_event_for_all_broadcast_sessions";
|
||||||
|
private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES =
|
||||||
|
"brodacast_response_exempted_roles";
|
||||||
|
private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS =
|
||||||
|
"brodacast_response_exempted_permissions";
|
||||||
|
|
||||||
public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS =
|
public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS =
|
||||||
COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR;
|
COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR;
|
||||||
@@ -2837,6 +2882,11 @@ public class AppStandbyController
|
|||||||
2 * ONE_MINUTE;
|
2 * ONE_MINUTE;
|
||||||
public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
|
public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
|
||||||
true;
|
true;
|
||||||
|
private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES = "";
|
||||||
|
private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = "";
|
||||||
|
|
||||||
|
private final TextUtils.SimpleStringSplitter mStringPipeSplitter =
|
||||||
|
new TextUtils.SimpleStringSplitter('|');
|
||||||
|
|
||||||
ConstantsObserver(Handler handler) {
|
ConstantsObserver(Handler handler) {
|
||||||
super(handler);
|
super(handler);
|
||||||
@@ -2989,6 +3039,20 @@ public class AppStandbyController
|
|||||||
KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS,
|
KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS,
|
||||||
DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS);
|
DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS);
|
||||||
break;
|
break;
|
||||||
|
case KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES:
|
||||||
|
mBroadcastResponseExemptedRoles = properties.getString(
|
||||||
|
KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES,
|
||||||
|
DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES);
|
||||||
|
mBroadcastResponseExemptedRolesList = splitPipeSeparatedString(
|
||||||
|
mBroadcastResponseExemptedRoles);
|
||||||
|
break;
|
||||||
|
case KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS:
|
||||||
|
mBroadcastResponseExemptedPermissions = properties.getString(
|
||||||
|
KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS,
|
||||||
|
DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS);
|
||||||
|
mBroadcastResponseExemptedPermissionsList = splitPipeSeparatedString(
|
||||||
|
mBroadcastResponseExemptedPermissions);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (!timeThresholdsUpdated
|
if (!timeThresholdsUpdated
|
||||||
&& (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD)
|
&& (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD)
|
||||||
@@ -3003,6 +3067,15 @@ public class AppStandbyController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> splitPipeSeparatedString(String string) {
|
||||||
|
final List<String> values = new ArrayList<>();
|
||||||
|
mStringPipeSplitter.setString(string);
|
||||||
|
while (mStringPipeSplitter.hasNext()) {
|
||||||
|
values.add(mStringPipeSplitter.next());
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateTimeThresholds() {
|
private void updateTimeThresholds() {
|
||||||
// Query the values as an atomic set.
|
// Query the values as an atomic set.
|
||||||
final DeviceConfig.Properties screenThresholdProperties =
|
final DeviceConfig.Properties screenThresholdProperties =
|
||||||
|
|||||||
@@ -23,15 +23,23 @@ import android.annotation.NonNull;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.ActivityManager.ProcessState;
|
import android.app.ActivityManager.ProcessState;
|
||||||
|
import android.app.role.OnRoleHoldersChangedListener;
|
||||||
|
import android.app.role.RoleManager;
|
||||||
import android.app.usage.BroadcastResponseStats;
|
import android.app.usage.BroadcastResponseStats;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.permission.PermissionManager;
|
||||||
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.LongArrayQueue;
|
import android.util.LongArrayQueue;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.os.BackgroundThread;
|
||||||
|
import com.android.internal.util.CollectionUtils;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -71,14 +79,33 @@ class BroadcastResponseStatsTracker {
|
|||||||
private SparseArray<SparseArray<UserBroadcastResponseStats>> mUserResponseStats =
|
private SparseArray<SparseArray<UserBroadcastResponseStats>> mUserResponseStats =
|
||||||
new SparseArray<>();
|
new SparseArray<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache of package names holding exempted roles.
|
||||||
|
*
|
||||||
|
* Contains the mapping of userId -> {roleName -> <packages>} data.
|
||||||
|
*/
|
||||||
|
// TODO: Use SparseArrayMap to simplify the logic.
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private SparseArray<ArrayMap<String, List<String>>> mExemptedRoleHoldersCache =
|
||||||
|
new SparseArray<>();
|
||||||
|
private final OnRoleHoldersChangedListener mRoleHoldersChangedListener =
|
||||||
|
this::onRoleHoldersChanged;
|
||||||
|
|
||||||
private AppStandbyInternal mAppStandby;
|
private AppStandbyInternal mAppStandby;
|
||||||
private BroadcastResponseStatsLogger mLogger;
|
private BroadcastResponseStatsLogger mLogger;
|
||||||
|
private RoleManager mRoleManager;
|
||||||
|
|
||||||
BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) {
|
BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) {
|
||||||
mAppStandby = appStandby;
|
mAppStandby = appStandby;
|
||||||
mLogger = new BroadcastResponseStatsLogger();
|
mLogger = new BroadcastResponseStatsLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onSystemServicesReady(Context context) {
|
||||||
|
mRoleManager = context.getSystemService(RoleManager.class);
|
||||||
|
mRoleManager.addOnRoleHoldersChangedListenerAsUser(BackgroundThread.getExecutor(),
|
||||||
|
mRoleHoldersChangedListener, UserHandle.ALL);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (206518114): Move all callbacks handling to a handler thread.
|
// TODO (206518114): Move all callbacks handling to a handler thread.
|
||||||
void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
|
void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
|
||||||
UserHandle targetUser, long idForResponseEvent,
|
UserHandle targetUser, long idForResponseEvent,
|
||||||
@@ -86,10 +113,19 @@ class BroadcastResponseStatsTracker {
|
|||||||
mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser,
|
mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser,
|
||||||
idForResponseEvent, timestampMs, targetUidProcState);
|
idForResponseEvent, timestampMs, targetUidProcState);
|
||||||
if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) {
|
if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) {
|
||||||
// No need to track the broadcast response state while the target app is
|
// No need to track the broadcast response stats while the target app is
|
||||||
// in the foreground.
|
// in the foreground.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (doesPackageHoldExemptedRole(targetPackage, targetUser)) {
|
||||||
|
// Package holds an exempted role, so no need to track the broadcast response stats.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (doesPackageHoldExemptedPermission(targetPackage, targetUser)) {
|
||||||
|
// Package holds an exempted permission, so no need to track the broadcast response
|
||||||
|
// stats
|
||||||
|
return;
|
||||||
|
}
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final ArraySet<BroadcastEvent> broadcastEvents =
|
final ArraySet<BroadcastEvent> broadcastEvents =
|
||||||
getOrCreateBroadcastEventsLocked(targetPackage, targetUser);
|
getOrCreateBroadcastEventsLocked(targetPackage, targetUser);
|
||||||
@@ -253,6 +289,62 @@ class BroadcastResponseStatsTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean doesPackageHoldExemptedRole(@NonNull String packageName, @NonNull UserHandle user) {
|
||||||
|
final List<String> exemptedRoles = mAppStandby.getBroadcastResponseExemptedRoles();
|
||||||
|
synchronized (mLock) {
|
||||||
|
for (int i = exemptedRoles.size() - 1; i >= 0; --i) {
|
||||||
|
final String roleName = exemptedRoles.get(i);
|
||||||
|
final List<String> roleHolders = getRoleHoldersLocked(roleName, user);
|
||||||
|
if (CollectionUtils.contains(roleHolders, packageName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean doesPackageHoldExemptedPermission(@NonNull String packageName,
|
||||||
|
@NonNull UserHandle user) {
|
||||||
|
final List<String> exemptedPermissions = mAppStandby
|
||||||
|
.getBroadcastResponseExemptedPermissions();
|
||||||
|
for (int i = exemptedPermissions.size() - 1; i >= 0; --i) {
|
||||||
|
final String permissionName = exemptedPermissions.get(i);
|
||||||
|
if (PermissionManager.checkPackageNamePermission(permissionName, packageName,
|
||||||
|
user.getIdentifier()) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
@Nullable
|
||||||
|
private List<String> getRoleHoldersLocked(@NonNull String roleName, @NonNull UserHandle user) {
|
||||||
|
ArrayMap<String, List<String>> roleHoldersForUser = mExemptedRoleHoldersCache.get(
|
||||||
|
user.getIdentifier());
|
||||||
|
if (roleHoldersForUser == null) {
|
||||||
|
roleHoldersForUser = new ArrayMap<>();
|
||||||
|
mExemptedRoleHoldersCache.put(user.getIdentifier(), roleHoldersForUser);
|
||||||
|
}
|
||||||
|
List<String> roleHolders = roleHoldersForUser.get(roleName);
|
||||||
|
if (roleHolders == null && mRoleManager != null) {
|
||||||
|
roleHolders = mRoleManager.getRoleHoldersAsUser(roleName, user);
|
||||||
|
roleHoldersForUser.put(roleName, roleHolders);
|
||||||
|
}
|
||||||
|
return roleHolders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
final ArrayMap<String, List<String>> roleHoldersForUser =
|
||||||
|
mExemptedRoleHoldersCache.get(user.getIdentifier());
|
||||||
|
if (roleHoldersForUser == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
roleHoldersForUser.remove(roleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onUserRemoved(@UserIdInt int userId) {
|
void onUserRemoved(@UserIdInt int userId) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mUserBroadcastEvents.remove(userId);
|
mUserBroadcastEvents.remove(userId);
|
||||||
@@ -260,6 +352,7 @@ class BroadcastResponseStatsTracker {
|
|||||||
for (int i = mUserResponseStats.size() - 1; i >= 0; --i) {
|
for (int i = mUserResponseStats.size() - 1; i >= 0; --i) {
|
||||||
mUserResponseStats.valueAt(i).remove(userId);
|
mUserResponseStats.valueAt(i).remove(userId);
|
||||||
}
|
}
|
||||||
|
mExemptedRoleHoldersCache.remove(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,6 +466,8 @@ class BroadcastResponseStatsTracker {
|
|||||||
ipw.println();
|
ipw.println();
|
||||||
dumpResponseStatsLocked(ipw);
|
dumpResponseStatsLocked(ipw);
|
||||||
ipw.println();
|
ipw.println();
|
||||||
|
dumpRoleHoldersLocked(ipw);
|
||||||
|
ipw.println();
|
||||||
mLogger.dumpLogs(ipw);
|
mLogger.dumpLogs(ipw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,5 +512,32 @@ class BroadcastResponseStatsTracker {
|
|||||||
}
|
}
|
||||||
ipw.decreaseIndent();
|
ipw.decreaseIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private void dumpRoleHoldersLocked(@NonNull IndentingPrintWriter ipw) {
|
||||||
|
ipw.println("Role holders:");
|
||||||
|
ipw.increaseIndent();
|
||||||
|
for (int userIdx = 0; userIdx < mExemptedRoleHoldersCache.size(); ++userIdx) {
|
||||||
|
final int userId = mExemptedRoleHoldersCache.keyAt(userIdx);
|
||||||
|
final ArrayMap<String, List<String>> roleHoldersForUser =
|
||||||
|
mExemptedRoleHoldersCache.valueAt(userIdx);
|
||||||
|
ipw.println("User " + userId + ":");
|
||||||
|
ipw.increaseIndent();
|
||||||
|
for (int roleIdx = 0; roleIdx < roleHoldersForUser.size(); ++roleIdx) {
|
||||||
|
final String roleName = roleHoldersForUser.keyAt(roleIdx);
|
||||||
|
final List<String> holders = roleHoldersForUser.valueAt(roleIdx);
|
||||||
|
ipw.print(roleName + ": ");
|
||||||
|
for (int holderIdx = 0; holderIdx < holders.size(); ++holderIdx) {
|
||||||
|
if (holderIdx > 0) {
|
||||||
|
ipw.print(", ");
|
||||||
|
}
|
||||||
|
ipw.print(holders.get(holderIdx));
|
||||||
|
}
|
||||||
|
ipw.println();
|
||||||
|
}
|
||||||
|
ipw.decreaseIndent();
|
||||||
|
}
|
||||||
|
ipw.decreaseIndent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -357,6 +357,7 @@ public class UsageStatsService extends SystemService implements
|
|||||||
getDpmInternal();
|
getDpmInternal();
|
||||||
// initialize mShortcutServiceInternal
|
// initialize mShortcutServiceInternal
|
||||||
getShortcutServiceInternal();
|
getShortcutServiceInternal();
|
||||||
|
mResponseStatsTracker.onSystemServicesReady(getContext());
|
||||||
|
|
||||||
if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
|
if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user