diff options
Diffstat (limited to 'services')
39 files changed, 1750 insertions, 598 deletions
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 17c7e0c..78cbac9 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -63,6 +63,7 @@ import android.util.AtomicFile; import android.util.AttributeSet; import android.util.Pair; import android.util.Slog; +import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; import android.util.Xml; @@ -171,6 +172,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private final SparseIntArray mLoadedUserIds = new SparseIntArray(); + private final SparseArray<ArraySet<String>> mWidgetPackages = new SparseArray<>(); + private final BackupRestoreController mBackupRestoreController; private final Context mContext; @@ -572,7 +575,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku widget.host = host; host.widgets.add(widget); - mWidgets.add(widget); + addWidgetLocked(widget); saveGroupStateAsync(userId); @@ -800,6 +803,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku widget.provider = provider; widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle(); + onWidgetProviderAddedOrChangedLocked(widget); + // We need to provide a default value for the widget category if it is not specified if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) { widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, @@ -1410,7 +1415,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku host.widgets.remove(widget); pruneHostLocked(host); - mWidgets.remove(widget); + removeWidgetLocked(widget); Provider provider = widget.provider; if (provider != null) { @@ -1874,7 +1879,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku updateAppWidgetInstanceLocked(widget, null, false); // clear out references to this appWidgetId widget.host.widgets.remove(widget); - mWidgets.remove(widget); + removeWidgetLocked(widget); widget.provider = null; pruneHostLocked(widget.host); widget.host = null; @@ -2277,14 +2282,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (version >= 0) { // Hooke'm up... - bindLoadedWidgets(loadedWidgets); + bindLoadedWidgetsLocked(loadedWidgets); // upgrade the database if needed performUpgradeLocked(version); } else { // failed reading, clean up Slog.w(TAG, "Failed to read state, clearing widgets and hosts."); - mWidgets.clear(); + clearWidgetsLocked(); mHosts.clear(); final int N = mProviders.size(); for (int i = 0; i < N; i++) { @@ -2293,7 +2298,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } - private void bindLoadedWidgets(List<LoadedWidgetState> loadedWidgets) { + private void bindLoadedWidgetsLocked(List<LoadedWidgetState> loadedWidgets) { final int loadedWidgetCount = loadedWidgets.size(); for (int i = loadedWidgetCount - 1; i >= 0; i--) { LoadedWidgetState loadedWidget = loadedWidgets.remove(i); @@ -2314,7 +2319,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku widget.provider.widgets.add(widget); widget.host.widgets.add(widget); - mWidgets.add(widget); + addWidgetLocked(widget); } } @@ -2346,6 +2351,91 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return null; } + /** + * Adds the widget to mWidgets and tracks the package name in mWidgetPackages. + */ + void addWidgetLocked(Widget widget) { + mWidgets.add(widget); + + onWidgetProviderAddedOrChangedLocked(widget); + } + + /** + * Checks if the provider is assigned and updates the mWidgetPackages to track packages + * that have bound widgets. + */ + void onWidgetProviderAddedOrChangedLocked(Widget widget) { + if (widget.provider == null) return; + + int userId = widget.provider.getUserId(); + ArraySet<String> packages = mWidgetPackages.get(userId); + if (packages == null) { + mWidgetPackages.put(userId, packages = new ArraySet<String>()); + } + packages.add(widget.provider.info.provider.getPackageName()); + } + + /** + * Removes a widget from mWidgets and updates the cache of bound widget provider packages. + * If there are other widgets with the same package, leaves it in the cache, otherwise it + * removes the associated package from the cache. + */ + void removeWidgetLocked(Widget widget) { + mWidgets.remove(widget); + + onWidgetRemovedLocked(widget); + } + + private void onWidgetRemovedLocked(Widget widget) { + if (widget.provider == null) return; + + final int userId = widget.provider.getUserId(); + final String packageName = widget.provider.info.provider.getPackageName(); + ArraySet<String> packages = mWidgetPackages.get(userId); + if (packages == null) { + return; + } + // Check if there is any other widget with the same package name. + // Remove packageName if none. + final int N = mWidgets.size(); + for (int i = 0; i < N; i++) { + Widget w = mWidgets.get(i); + if (w.provider == null) continue; + if (w.provider.getUserId() == userId + && packageName.equals(w.provider.info.provider.getPackageName())) { + return; + } + } + packages.remove(packageName); + } + + /** + * Clears all widgets and associated cache of packages with bound widgets. + */ + void clearWidgetsLocked() { + mWidgets.clear(); + + onWidgetsClearedLocked(); + } + + private void onWidgetsClearedLocked() { + mWidgetPackages.clear(); + } + + @Override + public boolean isBoundWidgetPackage(String packageName, int userId) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Only the system process can call this"); + } + synchronized (mLock) { + final ArraySet<String> packages = mWidgetPackages.get(userId); + if (packages != null) { + return packages.contains(packageName); + } + } + return false; + } + private void saveStateLocked(int userId) { tagProvidersAndHosts(); @@ -2692,7 +2782,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // as we do not want to make host callbacks and provider broadcasts // as the host and the provider will be killed. if (hostInUser && (!hasProvider || providerInUser)) { - mWidgets.remove(i); + removeWidgetLocked(widget); widget.host.widgets.remove(widget); widget.host = null; if (hasProvider) { @@ -3751,7 +3841,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Slog.i(TAG, "New restored id " + restoredId + " now " + id); } - mWidgets.add(id); + addWidgetLocked(id); } if (id.provider.info != null) { stashProviderRestoreUpdateLocked(id.provider, @@ -4013,7 +4103,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku host.widgets.remove(widget); provider.widgets.remove(widget); unbindAppWidgetRemoteViewsServicesLocked(widget); - mWidgets.remove(i); + removeWidgetLocked(widget); } } mPrunedApps.add(pkg); diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 1bed4f3..6c1023c 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -160,7 +160,7 @@ import libcore.io.IoUtils; public class BackupManagerService { private static final String TAG = "BackupManagerService"; - static final boolean DEBUG = true; + static final boolean DEBUG = false; static final boolean MORE_DEBUG = false; static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true; @@ -9368,44 +9368,47 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF throw new SecurityException("No permission to restore other packages"); } - // So far so good; we're allowed to try to restore this package. Now - // check whether there is data for it in the current dataset, falling back - // to the ancestral dataset if not. - long token = getAvailableRestoreToken(packageName); - if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName - + " token=" + Long.toHexString(token)); - - // If we didn't come up with a place to look -- no ancestral dataset and - // the app has never been backed up from this device -- there's nothing - // to do but return failure. - if (token == 0) { - if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring"); - return -1; - } - - String dirName; + // So far so good; we're allowed to try to restore this package. + long oldId = Binder.clearCallingIdentity(); try { - dirName = mRestoreTransport.transportDirName(); - } catch (RemoteException e) { - // Transport went AWOL; fail. - Slog.e(TAG, "Unable to contact transport for restore"); - return -1; - } + // Check whether there is data for it in the current dataset, falling back + // to the ancestral dataset if not. + long token = getAvailableRestoreToken(packageName); + if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + + " token=" + Long.toHexString(token)); + + // If we didn't come up with a place to look -- no ancestral dataset and + // the app has never been backed up from this device -- there's nothing + // to do but return failure. + if (token == 0) { + if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring"); + return -1; + } - // Stop the session timeout until we finalize the restore - mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT); + String dirName; + try { + dirName = mRestoreTransport.transportDirName(); + } catch (RemoteException e) { + // Transport went AWOL; fail. + Slog.e(TAG, "Unable to contact transport for restore"); + return -1; + } - // Ready to go: enqueue the restore request and claim success - long oldId = Binder.clearCallingIdentity(); - mWakelock.acquire(); - if (MORE_DEBUG) { - Slog.d(TAG, "restorePackage() : " + packageName); + // Stop the session timeout until we finalize the restore + mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT); + + // Ready to go: enqueue the restore request and claim success + mWakelock.acquire(); + if (MORE_DEBUG) { + Slog.d(TAG, "restorePackage() : " + packageName); + } + Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); + msg.obj = new RestoreParams(mRestoreTransport, dirName, + observer, token, app, 0); + mBackupHandler.sendMessage(msg); + } finally { + Binder.restoreCallingIdentity(oldId); } - Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); - msg.obj = new RestoreParams(mRestoreTransport, dirName, - observer, token, app, 0); - mBackupHandler.sendMessage(msg); - Binder.restoreCallingIdentity(oldId); return 0; } diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 17b4939..1366149 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -744,6 +744,11 @@ public class AppOpsService extends IAppOpsService.Stub { } } + @Override + public int permissionToOpCode(String permission) { + return AppOpsManager.permissionToOpCode(permission); + } + void finishOperationLocked(Op op) { if (op.nesting <= 1) { if (op.nesting == 1) { diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java index 9e28b64..26f4232 100644 --- a/services/core/java/com/android/server/AssetAtlasService.java +++ b/services/core/java/com/android/server/AssetAtlasService.java @@ -199,8 +199,6 @@ public class AssetAtlasService extends IAssetAtlas.Stub { private final ArrayList<Bitmap> mBitmaps; private final int mPixelCount; - private Bitmap mAtlasBitmap; - Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) { mBitmaps = bitmaps; mPixelCount = pixelCount; @@ -255,8 +253,9 @@ public class AssetAtlasService extends IAssetAtlas.Stub { // We always render the atlas into a bitmap. This bitmap is then // uploaded into the GraphicBuffer using OpenGL to swizzle the content - final Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight()); - if (canvas == null) return false; + final Bitmap atlasBitmap = Bitmap.createBitmap( + buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(atlasBitmap); final Atlas.Entry entry = new Atlas.Entry(); @@ -265,73 +264,58 @@ public class AssetAtlasService extends IAssetAtlas.Stub { int mapIndex = 0; boolean result = false; - try { - final long startRender = System.nanoTime(); - final int count = mBitmaps.size(); - - for (int i = 0; i < count; i++) { - final Bitmap bitmap = mBitmaps.get(i); - if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) { - // We have more bitmaps to pack than the current configuration - // says, we were most likely not able to detect a change in the - // list of preloaded drawables, abort and delete the configuration - if (mapIndex >= mAtlasMap.length) { - deleteDataFile(); - break; - } + final long startRender = System.nanoTime(); + final int count = mBitmaps.size(); - canvas.save(); - canvas.translate(entry.x, entry.y); - if (entry.rotated) { - canvas.translate(bitmap.getHeight(), 0.0f); - canvas.rotate(90.0f); - } - canvas.drawBitmap(bitmap, 0.0f, 0.0f, null); - canvas.restore(); - atlasMap[mapIndex++] = bitmap.getSkBitmap(); - atlasMap[mapIndex++] = entry.x; - atlasMap[mapIndex++] = entry.y; - atlasMap[mapIndex++] = entry.rotated ? 1 : 0; + for (int i = 0; i < count; i++) { + final Bitmap bitmap = mBitmaps.get(i); + if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) { + // We have more bitmaps to pack than the current configuration + // says, we were most likely not able to detect a change in the + // list of preloaded drawables, abort and delete the configuration + if (mapIndex >= mAtlasMap.length) { + deleteDataFile(); + break; } - } - - final long endRender = System.nanoTime(); - result = nUploadAtlas(buffer, mAtlasBitmap); - final long endUpload = System.nanoTime(); - if (DEBUG_ATLAS) { - float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f; - float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f; - Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)", - renderDuration + uploadDuration, renderDuration, uploadDuration)); + canvas.save(); + canvas.translate(entry.x, entry.y); + if (entry.rotated) { + canvas.translate(bitmap.getHeight(), 0.0f); + canvas.rotate(90.0f); + } + canvas.drawBitmap(bitmap, 0.0f, 0.0f, null); + canvas.restore(); + atlasMap[mapIndex++] = bitmap.refSkPixelRef(); + atlasMap[mapIndex++] = entry.x; + atlasMap[mapIndex++] = entry.y; + atlasMap[mapIndex++] = entry.rotated ? 1 : 0; } + } - } finally { - releaseCanvas(canvas); + final long endRender = System.nanoTime(); + releaseCanvas(canvas, atlasBitmap); + result = nUploadAtlas(buffer, atlasBitmap); + atlasBitmap.recycle(); + final long endUpload = System.nanoTime(); + + if (DEBUG_ATLAS) { + float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f; + float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f; + Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)", + renderDuration + uploadDuration, renderDuration, uploadDuration)); } return result; } /** - * Returns a Canvas for the specified buffer. If {@link #DEBUG_ATLAS_TEXTURE} - * is turned on, the returned Canvas will render into a local bitmap that - * will then be saved out to disk for debugging purposes. - * @param width - * @param height - */ - private Canvas acquireCanvas(int width, int height) { - mAtlasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - return new Canvas(mAtlasBitmap); - } - - /** * Releases the canvas used to render into the buffer. Calling this method * will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE} * is turend on, calling this method will write the content of the atlas * to disk in /data/system/atlas.png for debugging. */ - private void releaseCanvas(Canvas canvas) { + private void releaseCanvas(Canvas canvas, Bitmap atlasBitmap) { canvas.setBitmap(null); if (DEBUG_ATLAS_TEXTURE) { @@ -340,7 +324,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub { try { FileOutputStream out = new FileOutputStream(dataFile); - mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); + atlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); out.close(); } catch (FileNotFoundException e) { // Ignore @@ -348,8 +332,6 @@ public class AssetAtlasService extends IAssetAtlas.Stub { // Ignore } } - mAtlasBitmap.recycle(); - mAtlasBitmap = null; } } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index ef82bb7..1019faa 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -48,6 +48,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.util.Log; import java.io.FileDescriptor; @@ -443,6 +444,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { /** Internal death rec list */ Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>(); + @Override + public boolean isBleScanAlwaysAvailable() { + try { + return (Settings.Global.getInt(mContentResolver, + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0; + } catch (SettingNotFoundException e) { + } + return false; + } + public int updateBleAppCount(IBinder token, boolean enable) { if (enable) { ClientDeathRecipient r = mBleApps.get(token); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1a75b8a..8d1d124 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1141,7 +1141,13 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); if (nai != null) { synchronized (nai) { - return new NetworkCapabilities(nai.networkCapabilities); + NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities); + if (nai.lastValidated) { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + } else { + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + } + return nc; } } return null; diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 4fda370..759a6be 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -145,10 +145,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static final char INPUT_METHOD_SEPARATOR = ':'; private static final char INPUT_METHOD_SUBTYPE_SEPARATOR = ';'; - static final int MSG_SHOW_IM_PICKER = 1; - static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2; - static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3; - static final int MSG_SHOW_IM_CONFIG = 4; + static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1; + static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2; + static final int MSG_SHOW_IM_CONFIG = 3; static final int MSG_UNBIND_INPUT = 1000; static final int MSG_BIND_INPUT = 1010; @@ -2239,7 +2238,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void showInputMethodPickerFromClient(IInputMethodClient client) { + public void showInputMethodPickerFromClient( + IInputMethodClient client, int auxiliarySubtypeMode) { if (!calledFromValidUser()) { return; } @@ -2252,7 +2252,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Always call subtype picker, because subtype picker is a superset of input method // picker. - mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_PICKER); + mHandler.sendMessage(mCaller.obtainMessageI( + MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode)); } } @@ -2597,12 +2598,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub public boolean handleMessage(Message msg) { SomeArgs args; switch (msg.what) { - case MSG_SHOW_IM_PICKER: - showInputMethodMenu(); - return true; - case MSG_SHOW_IM_SUBTYPE_PICKER: - showInputMethodSubtypeMenu(); + final boolean showAuxSubtypes; + switch (msg.arg1) { + case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO: + // This is undocumented so far, but IMM#showInputMethodPicker() has been + // implemented so that auxiliary subtypes will be excluded when the soft + // keyboard is invisible. + showAuxSubtypes = mInputShown; + break; + case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES: + showAuxSubtypes = true; + break; + case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES: + showAuxSubtypes = false; + break; + default: + Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1); + return false; + } + showInputMethodMenu(showAuxSubtypes); return true; case MSG_SHOW_IM_SUBTYPE_ENABLER: @@ -2861,14 +2876,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // ---------------------------------------------------------------------- - private void showInputMethodMenu() { - showInputMethodMenuInternal(false); - } - - private void showInputMethodSubtypeMenu() { - showInputMethodMenuInternal(true); - } - private void showInputMethodAndSubtypeEnabler(String inputMethodId) { Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK @@ -2893,8 +2900,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure(); } - private void showInputMethodMenuInternal(boolean showSubtypes) { - if (DEBUG) Slog.v(TAG, "Show switching menu"); + private void showInputMethodMenu(boolean showAuxSubtypes) { + if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes); final Context context = mContext; final boolean isScreenLocked = isScreenLocked(); @@ -2915,7 +2922,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final List<ImeSubtypeListItem> imList = mSwitchingController.getSortedInputMethodAndSubtypeListLocked( - showSubtypes, mInputShown, isScreenLocked); + true /* showSubtypes */, showAuxSubtypes, isScreenLocked); if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) { final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked(); @@ -3016,7 +3023,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub }; mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener); - if (showSubtypes && !isScreenLocked) { + if (!isScreenLocked) { final OnClickListener positiveListener = new OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 8c6e290..bc93268 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -678,7 +678,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { handleRemoveListLocked(); } broadcastCallStateChanged(state, incomingNumber, - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); + SubscriptionManager.INVALID_SUBSCRIPTION_ID); } public void notifyCallStateForSubscriber(int subId, int state, String incomingNumber) { @@ -1374,6 +1374,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } + /** + * Broadcasts an intent notifying apps of a phone state change. {@code subId} can be + * a valid subId, in which case this function fires a subId-specific intent, or it + * can be {@code SubscriptionManager.INVALID_SUBSCRIPTION_ID}, in which case we send + * a global state change broadcast ({@code TelephonyManager.ACTION_PHONE_STATE_CHANGED}). + */ private void broadcastCallStateChanged(int state, String incomingNumber, int subId) { long ident = Binder.clearCallingIdentity(); try { @@ -1394,7 +1400,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!TextUtils.isEmpty(incomingNumber)) { intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); } - intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + + // If a valid subId was specified, we should fire off a subId-specific state + // change intent and include the subId. + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + intent.setAction(PhoneConstants.ACTION_SUBSCRIPTION_PHONE_STATE_CHANGED); + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + } + mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.READ_PHONE_STATE, AppOpsManager.OP_READ_PHONE_STATE); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 50f7328..82dbfee 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -47,6 +47,7 @@ import android.app.ProfilerInfo; import android.app.usage.UsageEvents; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; +import android.content.pm.PermissionInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Point; @@ -413,6 +414,11 @@ public final class ActivityManagerService extends ActivityManagerNative ActivityRecord mFocusedActivity = null; /** + * User id of the last activity mFocusedActivity was set to. + */ + private int mLastFocusedUserId; + + /** * List of intents that were used to start the most recent tasks. */ private final RecentTasks mRecentTasks; @@ -2560,19 +2566,32 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setFocusedApp(r.appToken, true); } applyUpdateLockStateLocked(r); - if (last != null && last.userId != mFocusedActivity.userId) { + if (mFocusedActivity.userId != mLastFocusedUserId) { mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG); mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, mFocusedActivity.userId, 0)); + mLastFocusedUserId = mFocusedActivity.userId; } } - EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY, mCurrentUserId, + EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY, + mFocusedActivity == null ? -1 : mFocusedActivity.userId, mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName); } final void clearFocusedActivity(ActivityRecord r) { if (mFocusedActivity == r) { + ActivityStack stack = mStackSupervisor.getFocusedStack(); + if (stack != null) { + ActivityRecord top = stack.topActivity(); + if (top != null && top.userId != mLastFocusedUserId) { + mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG); + mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, + top.userId, 0)); + mLastFocusedUserId = top.userId; + } + } mFocusedActivity = null; + EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY, -1, "NULL"); } } @@ -3113,8 +3132,16 @@ public final class ActivityManagerService extends ActivityManagerNative checkTime(startTime, "startProcess: done updating cpu stats"); try { - int uid = app.uid; + try { + if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) { + // This is caught below as if we had failed to fork zygote + throw new RuntimeException("Package " + app.info.packageName + " is frozen!"); + } + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + int uid = app.uid; int[] gids = null; int mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT; if (!app.isolated) { @@ -3124,7 +3151,7 @@ public final class ActivityManagerService extends ActivityManagerNative permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName, app.userId); } catch (RemoteException e) { - Slog.w(TAG, "Unable to retrieve gids", e); + throw e.rethrowAsRuntimeException(); } /* @@ -3177,6 +3204,10 @@ public final class ActivityManagerService extends ActivityManagerNative debugFlags |= Zygote.DEBUG_ENABLE_JIT; } } + String genCFIDebugProperty = SystemProperties.get("debug.gencfi"); + if ("true".equals(genCFIDebugProperty)) { + debugFlags |= Zygote.DEBUG_GENERATE_CFI; + } if ("1".equals(SystemProperties.get("debug.jni.logging"))) { debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING; } @@ -6607,6 +6638,18 @@ public final class ActivityManagerService extends ActivityManagerNative return mActivityManagerService.mContext.getPackageManager() .getPackagesForUid(uid); } + + @Override + public boolean isRuntimePermission(String permission) { + try { + PermissionInfo info = mActivityManagerService.mContext.getPackageManager() + .getPermissionInfo(permission, 0); + return info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS; + } catch (NameNotFoundException nnfe) { + Slog.e(TAG, "No such permission: "+ permission, nnfe); + } + return false; + } } class IntentFirewallInterface implements IntentFirewall.AMSInterface { @@ -10729,9 +10772,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void killUid(int uid, String reason) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("killUid only available to the system"); - } + enforceCallingPermission(Manifest.permission.KILL_UID, "killUid"); synchronized (this) { killPackageProcessesLocked(null, UserHandle.getAppId(uid), UserHandle.getUserId(uid), ProcessList.FOREGROUND_APP_ADJ-1, false, true, true, false, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index eb28ed0..06fba34 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -65,6 +65,7 @@ import android.media.SoundPool; import android.media.VolumePolicy; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; +import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.IAudioPolicyCallback; @@ -206,6 +207,7 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22; private static final int MSG_PERSIST_MICROPHONE_MUTE = 23; private static final int MSG_UNMUTE_STREAM = 24; + private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -4337,6 +4339,9 @@ public class AudioService extends IAudioService.Stub { case MSG_UNMUTE_STREAM: onUnmuteStream(msg.arg1, msg.arg2); break; + case MSG_DYN_POLICY_MIX_STATE_UPDATE: + onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1); + break; } } } @@ -5758,6 +5763,8 @@ public class AudioService extends IAudioService.Stub { //========================================================================================== public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb, boolean hasFocusListener) { + AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback); + if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder() + " with config:" + policyConfig); String regId = null; @@ -5853,6 +5860,39 @@ public class AudioService extends IAudioService.Stub { } //====================== + // Audio policy callback from AudioSystem + //====================== + private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback = + new AudioSystem.DynamicPolicyCallback() { + public void onDynamicPolicyMixStateUpdate(String regId, int state) { + if (!TextUtils.isEmpty(regId)) { + sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE, + state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/); + } + } + }; + + private void onDynPolicyMixStateUpdate(String regId, int state) { + if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")"); + synchronized (mAudioPolicies) { + for (AudioPolicyProxy policy : mAudioPolicies.values()) { + for (AudioMix mix : policy.getMixes()) { + if (mix.getRegistration().equals(regId)) { + try { + policy.mPolicyCallback.notifyMixStateUpdate(regId, state); + } catch (RemoteException e) { + Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback " + + policy.mPolicyCallback.asBinder(), e); + } + return; + } + } + } + } + + } + + //====================== // Audio policy proxy //====================== /** @@ -5861,8 +5901,7 @@ public class AudioService extends IAudioService.Stub { */ public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient { private static final String TAG = "AudioPolicyProxy"; - AudioPolicyConfig mConfig; - IAudioPolicyCallback mPolicyToken; + IAudioPolicyCallback mPolicyCallback; boolean mHasFocusListener; /** * Audio focus ducking behavior for an audio policy. @@ -5877,19 +5916,19 @@ public class AudioService extends IAudioService.Stub { boolean hasFocusListener) { super(config); setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++)); - mPolicyToken = token; + mPolicyCallback = token; mHasFocusListener = hasFocusListener; if (mHasFocusListener) { - mMediaFocusControl.addFocusFollower(mPolicyToken); + mMediaFocusControl.addFocusFollower(mPolicyCallback); } connectMixes(); } public void binderDied() { synchronized (mAudioPolicies) { - Log.i(TAG, "audio policy " + mPolicyToken + " died"); + Log.i(TAG, "audio policy " + mPolicyCallback + " died"); release(); - mAudioPolicies.remove(mPolicyToken.asBinder()); + mAudioPolicies.remove(mPolicyCallback.asBinder()); } } @@ -5902,7 +5941,7 @@ public class AudioService extends IAudioService.Stub { mMediaFocusControl.setDuckingInExtPolicyAvailable(false); } if (mHasFocusListener) { - mMediaFocusControl.removeFocusFollower(mPolicyToken); + mMediaFocusControl.removeFocusFollower(mPolicyCallback); } AudioSystem.registerPolicyMixes(mMixes, false); } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 7cccef2..3dc282b 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -52,6 +52,7 @@ import android.content.pm.RegisteredServicesCache; import android.content.pm.RegisteredServicesCacheListener; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; +import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.BatteryStats; @@ -99,6 +100,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; @@ -157,7 +159,19 @@ public class SyncManager { /** * How long to wait before considering an active sync to have timed-out, and cancelling it. */ - private static final long ACTIVE_SYNC_TIMEOUT_MILLIS = 30L * 60 * 1000; // 30 mins. + private static final long ACTIVE_SYNC_TIMEOUT_MILLIS = 30L * 60 * 1000; // 30 mins + + /** + * How long to delay each queued {@link SyncHandler} message that may have occurred before boot + * or befor the device became provisioned. + */ + private static final long PER_SYNC_BOOT_DELAY_MILLIS = 3000L; // 3 seconds + + /** + * The maximum amount of time we're willing to delay syncs out of boot, after device has been + * provisioned, etc. + */ + private static final long MAX_SYNC_BOOT_DELAY_MILLIS = 120000L; // 2 minutes private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/"; private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm"; @@ -198,6 +212,9 @@ public class SyncManager { // its accessor, getConnManager(). private ConnectivityManager mConnManagerDoNotUseDirectly; + /** Track whether the device has already been provisioned. */ + private boolean mProvisioned; + protected SyncAdaptersCache mSyncAdapters; private final AppIdleMonitor mAppIdleMonitor; @@ -242,6 +259,7 @@ public class SyncManager { private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + mBootCompleted = true; mSyncHandler.onBootCompleted(); } }; @@ -491,12 +509,41 @@ public class SyncManager { mSyncStorageEngine.addStatusChangeListener( ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() { - @Override - public void onStatusChanged(int which) { - // force the sync loop to run if the settings change - sendCheckAlarmsMessage(); + @Override + public void onStatusChanged(int which) { + // force the sync loop to run if the settings change + sendCheckAlarmsMessage(); + } + }); + + mProvisioned = isDeviceProvisioned(); + if (!mProvisioned) { + final ContentResolver resolver = context.getContentResolver(); + ContentObserver provisionedObserver = + new ContentObserver(null /* current thread */) { + public void onChange(boolean selfChange) { + mProvisioned |= isDeviceProvisioned(); + if (mProvisioned) { + mSyncHandler.onDeviceProvisioned(); + resolver.unregisterContentObserver(this); + } + } + }; + + synchronized (mSyncHandler) { + resolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), + false /* notifyForDescendents */, + provisionedObserver); + + // The device *may* have been provisioned while we were registering above observer. + // Check again to make sure. + mProvisioned |= isDeviceProvisioned(); + if (mProvisioned) { + resolver.unregisterContentObserver(provisionedObserver); + } } - }); + } if (!factoryTest) { // Register for account list updates for all users @@ -510,6 +557,10 @@ public class SyncManager { mSyncRandomOffsetMillis = mSyncStorageEngine.getSyncRandomOffset() * 1000; } + private boolean isDeviceProvisioned() { + final ContentResolver resolver = mContext.getContentResolver(); + return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0); + } /** * Return a random value v that satisfies minValue <= v < maxValue. The difference between * maxValue and minValue must be less than Integer.MAX_VALUE. @@ -2000,20 +2051,36 @@ public class SyncManager { public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker(); private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap(); - private List<Message> mBootQueue = new ArrayList<Message>(); + private List<Message> mUnreadyQueue = new ArrayList<Message>(); - public void onBootCompleted() { + void onBootCompleted() { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Boot completed, clearing boot queue."); } doDatabaseCleanup(); synchronized(this) { // Dispatch any stashed messages. - for (Message message : mBootQueue) { - sendMessage(message); + maybeEmptyUnreadyQueueLocked(); + } + } + + void onDeviceProvisioned() { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "mProvisioned=" + mProvisioned); + } + synchronized (this) { + maybeEmptyUnreadyQueueLocked(); + } + } + + private void maybeEmptyUnreadyQueueLocked() { + if (mProvisioned && mBootCompleted) { + // Dispatch any stashed messages. + for (int i=0; i<mUnreadyQueue.size(); i++) { + sendMessageDelayed(mUnreadyQueue.get(i), + Math.max(PER_SYNC_BOOT_DELAY_MILLIS * i, MAX_SYNC_BOOT_DELAY_MILLIS)); } - mBootQueue = null; - mBootCompleted = true; + mUnreadyQueue = null; } } @@ -2030,20 +2097,23 @@ public class SyncManager { } /** - * Stash any messages that come to the handler before boot is complete. - * {@link #onBootCompleted()} will disable this and dispatch all the messages collected. + * Stash any messages that come to the handler before boot is complete or before the device + * is properly provisioned (i.e. out of set-up wizard). + * {@link #onBootCompleted()} and {@link #onDeviceProvisioned(boolean)} both need to come + * in before we start syncing. * @param msg Message to dispatch at a later point. * @return true if a message was enqueued, false otherwise. This is to avoid losing the * message if we manage to acquire the lock but by the time we do boot has completed. */ private boolean tryEnqueueMessageUntilReadyToRun(Message msg) { synchronized (this) { - if (!mBootCompleted) { + if (!mBootCompleted || !mProvisioned) { // Need to copy the message bc looper will recycle it. - mBootQueue.add(Message.obtain(msg)); + mUnreadyQueue.add(Message.obtain(msg)); return true; + } else { + return false; } - return false; } } @@ -2100,7 +2170,7 @@ public class SyncManager { } cancelActiveSync(expiredContext.mSyncOperation.target, expiredContext.mSyncOperation.extras); - nextPendingSyncTime = maybeStartNextSyncLocked(); + nextPendingSyncTime = maybeStartNextSyncH(); break; case SyncHandler.MESSAGE_CANCEL: { @@ -2111,7 +2181,7 @@ public class SyncManager { + payload + " bundle: " + extras); } cancelActiveSyncLocked(payload, extras); - nextPendingSyncTime = maybeStartNextSyncLocked(); + nextPendingSyncTime = maybeStartNextSyncH(); break; } @@ -2120,17 +2190,17 @@ public class SyncManager { Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_SYNC_FINISHED"); } SyncHandlerMessagePayload payload = (SyncHandlerMessagePayload) msg.obj; - if (!isSyncStillActive(payload.activeSyncContext)) { + if (!isSyncStillActiveH(payload.activeSyncContext)) { Log.d(TAG, "handleSyncHandlerMessage: dropping since the " + "sync is no longer active: " + payload.activeSyncContext); break; } - runSyncFinishedOrCanceledLocked(payload.syncResult, + runSyncFinishedOrCanceledH(payload.syncResult, payload.activeSyncContext); // since a sync just finished check if it is time to start a new sync - nextPendingSyncTime = maybeStartNextSyncLocked(); + nextPendingSyncTime = maybeStartNextSyncH(); break; case SyncHandler.MESSAGE_SERVICE_CONNECTED: { @@ -2140,7 +2210,7 @@ public class SyncManager { + msgData.activeSyncContext); } // check that this isn't an old message - if (isSyncStillActive(msgData.activeSyncContext)) { + if (isSyncStillActiveH(msgData.activeSyncContext)) { runBoundToAdapter( msgData.activeSyncContext, msgData.adapter); @@ -2156,7 +2226,7 @@ public class SyncManager { + currentSyncContext); } // check that this isn't an old message - if (isSyncStillActive(currentSyncContext)) { + if (isSyncStillActiveH(currentSyncContext)) { // cancel the sync if we have a syncadapter, which means one is // outstanding try { @@ -2174,10 +2244,10 @@ public class SyncManager { // which is a soft error SyncResult syncResult = new SyncResult(); syncResult.stats.numIoExceptions++; - runSyncFinishedOrCanceledLocked(syncResult, currentSyncContext); + runSyncFinishedOrCanceledH(syncResult, currentSyncContext); // since a sync just finished check if it is time to start a new sync - nextPendingSyncTime = maybeStartNextSyncLocked(); + nextPendingSyncTime = maybeStartNextSyncH(); } break; @@ -2190,7 +2260,7 @@ public class SyncManager { } mAlarmScheduleTime = null; try { - nextPendingSyncTime = maybeStartNextSyncLocked(); + nextPendingSyncTime = maybeStartNextSyncH(); } finally { mHandleAlarmWakeLock.release(); } @@ -2201,7 +2271,7 @@ public class SyncManager { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_CHECK_ALARMS"); } - nextPendingSyncTime = maybeStartNextSyncLocked(); + nextPendingSyncTime = maybeStartNextSyncH(); break; } } finally { @@ -2393,7 +2463,7 @@ public class SyncManager { 0 : (earliestFuturePollTime - nowAbsolute)); } - private long maybeStartNextSyncLocked() { + private long maybeStartNextSyncH() { final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (isLoggable) Log.v(TAG, "maybeStartNextSync"); @@ -2612,7 +2682,7 @@ public class SyncManager { } if (toReschedule != null) { - runSyncFinishedOrCanceledLocked(null, toReschedule); + runSyncFinishedOrCanceledH(null, toReschedule); scheduleSyncOperation(toReschedule.mSyncOperation); } synchronized (mSyncQueue) { @@ -2845,14 +2915,14 @@ public class SyncManager { false /* no config settings */)) { continue; } - runSyncFinishedOrCanceledLocked(null /* no result since this is a cancel */, + runSyncFinishedOrCanceledH(null /* no result since this is a cancel */, activeSyncContext); } } } - private void runSyncFinishedOrCanceledLocked(SyncResult syncResult, - ActiveSyncContext activeSyncContext) { + private void runSyncFinishedOrCanceledH(SyncResult syncResult, + ActiveSyncContext activeSyncContext) { boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); final SyncOperation syncOperation = activeSyncContext.mSyncOperation; @@ -3257,7 +3327,7 @@ public class SyncManager { } } - private boolean isSyncStillActive(ActiveSyncContext activeSyncContext) { + private boolean isSyncStillActiveH(ActiveSyncContext activeSyncContext) { for (ActiveSyncContext sync : mActiveSyncContexts) { if (sync == activeSyncContext) { return true; diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 6b5908d..ed8519a 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -16,14 +16,15 @@ package com.android.server.fingerprint; +import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.MessageQueue; import android.os.RemoteException; -import android.util.ArrayMap; import android.util.Slog; import com.android.server.SystemService; @@ -39,6 +40,7 @@ import static android.Manifest.permission.USE_FINGERPRINT; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -55,6 +57,8 @@ public class FingerprintService extends SystemService { private ClientMonitor mEnrollClient = null; private ClientMonitor mRemoveClient = null; + private final AppOpsManager mAppOps; + private static final int MSG_NOTIFY = 10; private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute @@ -96,6 +100,7 @@ public class FingerprintService extends SystemService { public FingerprintService(Context context) { super(context); mContext = context; + mAppOps = context.getSystemService(AppOpsManager.class); nativeInit(Looper.getMainLooper().getQueue(), this); } @@ -361,6 +366,13 @@ public class FingerprintService extends SystemService { "Must have " + permission + " permission."); } + private boolean canUserFingerPrint(String opPackageName) { + checkPermission(USE_FINGERPRINT); + + return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(), + opPackageName) == AppOpsManager.MODE_ALLOWED; + } + private class ClientMonitor implements IBinder.DeathRecipient { IBinder token; IFingerprintServiceReceiver receiver; @@ -522,8 +534,11 @@ public class FingerprintService extends SystemService { @Override // Binder call public void authenticate(final IBinder token, final long opId, final int groupId, - final IFingerprintServiceReceiver receiver, final int flags) { + final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) { checkPermission(USE_FINGERPRINT); + if (!canUserFingerPrint(opPackageName)) { + return; + } mHandler.post(new Runnable() { @Override public void run() { @@ -535,8 +550,10 @@ public class FingerprintService extends SystemService { @Override // Binder call - public void cancelAuthentication(final IBinder token) { - checkPermission(USE_FINGERPRINT); + public void cancelAuthentication(final IBinder token, String opPackageName) { + if (!canUserFingerPrint(opPackageName)) { + return; + } mHandler.post(new Runnable() { @Override public void run() { @@ -561,8 +578,10 @@ public class FingerprintService extends SystemService { @Override // Binder call - public boolean isHardwareDetected(long deviceId) { - checkPermission(USE_FINGERPRINT); + public boolean isHardwareDetected(long deviceId, String opPackageName) { + if (!canUserFingerPrint(opPackageName)) { + return false; + } return mHalDeviceId != 0; // TODO } @@ -580,21 +599,27 @@ public class FingerprintService extends SystemService { @Override // Binder call - public List<Fingerprint> getEnrolledFingerprints(int groupId) { - checkPermission(USE_FINGERPRINT); + public List<Fingerprint> getEnrolledFingerprints(int groupId, String opPackageName) { + if (!canUserFingerPrint(opPackageName)) { + return Collections.emptyList(); + } return FingerprintService.this.getEnrolledFingerprints(groupId); } @Override // Binder call - public boolean hasEnrolledFingerprints(int groupId) { - checkPermission(USE_FINGERPRINT); + public boolean hasEnrolledFingerprints(int groupId, String opPackageName) { + if (!canUserFingerPrint(opPackageName)) { + return false; + } return FingerprintService.this.hasEnrolledFingerprints(groupId); } @Override - public long getAuthenticatorId() { - checkPermission(USE_FINGERPRINT); + public long getAuthenticatorId(String opPackageName) { + if (!canUserFingerPrint(opPackageName)) { + return 0; + } return nativeGetAuthenticatorId(); } } diff --git a/services/core/java/com/android/server/net/DelayedDiskWrite.java b/services/core/java/com/android/server/net/DelayedDiskWrite.java index 6ed277d..8f09eb7 100644 --- a/services/core/java/com/android/server/net/DelayedDiskWrite.java +++ b/services/core/java/com/android/server/net/DelayedDiskWrite.java @@ -38,6 +38,10 @@ public class DelayedDiskWrite { } public void write(final String filePath, final Writer w) { + write(filePath, w, true); + } + + public void write(final String filePath, final Writer w, final boolean open) { if (TextUtils.isEmpty(filePath)) { throw new IllegalArgumentException("empty file path"); } @@ -54,16 +58,18 @@ public class DelayedDiskWrite { mDiskWriteHandler.post(new Runnable() { @Override public void run() { - doWrite(filePath, w); + doWrite(filePath, w, open); } }); } - private void doWrite(String filePath, Writer w) { + private void doWrite(String filePath, Writer w, boolean open) { DataOutputStream out = null; try { - out = new DataOutputStream(new BufferedOutputStream( + if (open) { + out = new DataOutputStream(new BufferedOutputStream( new FileOutputStream(filePath))); + } w.onWriteCalled(out); } catch (IOException e) { loge("Error writing data file " + filePath); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 50e03a2..0035d01 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -561,9 +561,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int callingUid = Binder.getCallingUid(); final DevicePolicyManagerInternal dpmi = LocalServices.getService( DevicePolicyManagerInternal.class); - if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) - || dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) { + + // Device owners are also profile owners so it is enough to check for that. + if (dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) { return; } } diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java new file mode 100644 index 0000000..28da73c --- /dev/null +++ b/services/core/java/com/android/server/notification/CalendarTracker.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015 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.server.notification; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; +import android.provider.BaseColumns; +import android.provider.CalendarContract.Attendees; +import android.provider.CalendarContract.Instances; +import android.service.notification.ZenModeConfig.EventInfo; +import android.util.Log; + +import java.io.PrintWriter; +import java.util.Date; +import java.util.Objects; + +public class CalendarTracker { + private static final String TAG = "ConditionProviders.CT"; + private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG); + private static final boolean DEBUG_ATTENDEES = false; + + private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000; + + private static final String[] INSTANCE_PROJECTION = { + Instances.BEGIN, + Instances.END, + Instances.TITLE, + Instances.VISIBLE, + Instances.EVENT_ID, + Instances.OWNER_ACCOUNT, + Instances.CALENDAR_ID, + Instances.AVAILABILITY, + }; + + private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC"; + + private static final String[] ATTENDEE_PROJECTION = { + Attendees.EVENT_ID, + Attendees.ATTENDEE_EMAIL, + Attendees.ATTENDEE_STATUS, + }; + + private static final String ATTENDEE_SELECTION = Attendees.EVENT_ID + " = ? AND " + + Attendees.ATTENDEE_EMAIL + " = ?"; + + private final Context mContext; + + private Callback mCallback; + private boolean mRegistered; + + public CalendarTracker(Context context) { + mContext = context; + } + + public void setCallback(Callback callback) { + if (mCallback == callback) return; + mCallback = callback; + setRegistered(mCallback != null); + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("mCallback="); pw.println(mCallback); + pw.print(prefix); pw.print("mRegistered="); pw.println(mRegistered); + } + + public void dumpContent(Uri uri) { + Log.d(TAG, "dumpContent: " + uri); + final Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null); + try { + int r = 0; + while (cursor.moveToNext()) { + Log.d(TAG, "Row " + (++r) + ": id=" + + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID))); + for (int i = 0; i < cursor.getColumnCount(); i++) { + final String name = cursor.getColumnName(i); + final int type = cursor.getType(i); + Object o = null; + String typeName = null; + switch (type) { + case Cursor.FIELD_TYPE_INTEGER: + o = cursor.getLong(i); + typeName = "INTEGER"; + break; + case Cursor.FIELD_TYPE_STRING: + o = cursor.getString(i); + typeName = "STRING"; + break; + case Cursor.FIELD_TYPE_NULL: + o = null; + typeName = "NULL"; + break; + default: + throw new UnsupportedOperationException("type: " + type); + } + if (name.equals(BaseColumns._ID) + || name.toLowerCase().contains("sync") + || o == null) { + continue; + } + Log.d(TAG, " " + name + "(" + typeName + ")=" + o); + } + } + Log.d(TAG, " " + uri + " " + r + " rows"); + } finally { + cursor.close(); + } + } + + + + public CheckEventResult checkEvent(EventInfo filter, long time) { + final Uri.Builder uriBuilder = Instances.CONTENT_URI.buildUpon(); + ContentUris.appendId(uriBuilder, time); + ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD); + final Uri uri = uriBuilder.build(); + final Cursor cursor = mContext.getContentResolver().query(uri, INSTANCE_PROJECTION, null, + null, INSTANCE_ORDER_BY); + final CheckEventResult result = new CheckEventResult(); + result.recheckAt = time + EVENT_CHECK_LOOKAHEAD; + try { + while (cursor.moveToNext()) { + final long begin = cursor.getLong(0); + final long end = cursor.getLong(1); + final String title = cursor.getString(2); + final boolean visible = cursor.getInt(3) == 1; + final int eventId = cursor.getInt(4); + final String owner = cursor.getString(5); + final long calendarId = cursor.getLong(6); + final int availability = cursor.getInt(7); + if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s", title, + new Date(begin), new Date(end), visible, availabilityToString(availability), + eventId, owner, calendarId)); + final boolean meetsTime = time >= begin && time < end; + final boolean meetsCalendar = visible + && (filter.calendar == 0 || filter.calendar == calendarId) + && availability != Instances.AVAILABILITY_FREE; + if (meetsCalendar) { + if (DEBUG) Log.d(TAG, " MEETS CALENDAR"); + final boolean meetsAttendee = meetsAttendee(filter, eventId, owner); + if (meetsAttendee) { + if (DEBUG) Log.d(TAG, " MEETS ATTENDEE"); + if (meetsTime) { + if (DEBUG) Log.d(TAG, " MEETS TIME"); + result.inEvent = true; + } + if (begin > time && begin < result.recheckAt) { + result.recheckAt = begin; + } else if (end > time && end < result.recheckAt) { + result.recheckAt = end; + } + } + } + } + } finally { + cursor.close(); + } + return result; + } + + private boolean meetsAttendee(EventInfo filter, int eventId, String email) { + String selection = ATTENDEE_SELECTION; + String[] selectionArgs = { Integer.toString(eventId), email }; + if (DEBUG_ATTENDEES) { + selection = null; + selectionArgs = null; + } + final Cursor cursor = mContext.getContentResolver().query(Attendees.CONTENT_URI, + ATTENDEE_PROJECTION, selection, selectionArgs, null); + try { + if (cursor.getCount() == 0) { + if (DEBUG) Log.d(TAG, "No attendees found"); + return true; + } + boolean rt = false; + while (cursor.moveToNext()) { + final long rowEventId = cursor.getLong(0); + final String rowEmail = cursor.getString(1); + final int status = cursor.getInt(2); + final boolean meetsReply = meetsReply(filter.reply, status); + if (DEBUG) Log.d(TAG, (DEBUG_ATTENDEES ? String.format( + "rowEventId=%s, rowEmail=%s, ", rowEventId, rowEmail) : "") + + String.format("status=%s, meetsReply=%s", + attendeeStatusToString(status), meetsReply)); + final boolean eventMeets = rowEventId == eventId && Objects.equals(rowEmail, email) + && meetsReply; + rt |= eventMeets; + } + return rt; + } finally { + cursor.close(); + } + } + + private void setRegistered(boolean registered) { + if (mRegistered == registered) return; + final ContentResolver cr = mContext.getContentResolver(); + if (mRegistered) { + cr.unregisterContentObserver(mObserver); + } + mRegistered = registered; + if (mRegistered) { + cr.registerContentObserver(Instances.CONTENT_URI, false, mObserver); + } + } + + private static String attendeeStatusToString(int status) { + switch (status) { + case Attendees.ATTENDEE_STATUS_NONE: return "ATTENDEE_STATUS_NONE"; + case Attendees.ATTENDEE_STATUS_ACCEPTED: return "ATTENDEE_STATUS_ACCEPTED"; + case Attendees.ATTENDEE_STATUS_DECLINED: return "ATTENDEE_STATUS_DECLINED"; + case Attendees.ATTENDEE_STATUS_INVITED: return "ATTENDEE_STATUS_INVITED"; + case Attendees.ATTENDEE_STATUS_TENTATIVE: return "ATTENDEE_STATUS_TENTATIVE"; + default: return "ATTENDEE_STATUS_UNKNOWN_" + status; + } + } + + private static String availabilityToString(int availability) { + switch (availability) { + case Instances.AVAILABILITY_BUSY: return "AVAILABILITY_BUSY"; + case Instances.AVAILABILITY_FREE: return "AVAILABILITY_FREE"; + case Instances.AVAILABILITY_TENTATIVE: return "AVAILABILITY_TENTATIVE"; + default: return "AVAILABILITY_UNKNOWN_" + availability; + } + } + + private static boolean meetsReply(int reply, int attendeeStatus) { + switch (reply) { + case EventInfo.REPLY_YES: + return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED; + case EventInfo.REPLY_YES_OR_MAYBE: + return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED + || attendeeStatus == Attendees.ATTENDEE_STATUS_TENTATIVE; + case EventInfo.REPLY_ANY_EXCEPT_NO: + return attendeeStatus != Attendees.ATTENDEE_STATUS_DECLINED; + default: + return false; + } + } + + private final ContentObserver mObserver = new ContentObserver(null) { + @Override + public void onChange(boolean selfChange, Uri u) { + if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u); + mCallback.onChanged(); + } + + @Override + public void onChange(boolean selfChange) { + if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange); + } + }; + + public static class CheckEventResult { + public boolean inEvent; + public long recheckAt; + } + + public interface Callback { + void onChanged(); + } + +} diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index b36fcd2..8c6afaf 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -121,6 +121,9 @@ public class ConditionProviders extends ManagedServices { @Override public void onBootPhaseAppsCanStart() { super.onBootPhaseAppsCanStart(); + for (int i = 0; i < mSystemConditionProviders.size(); i++) { + mSystemConditionProviders.valueAt(i).onBootComplete(); + } if (mCallback != null) { mCallback.onBootComplete(); } diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java index 6a04688..07903e9 100644 --- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java +++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java @@ -34,12 +34,11 @@ import android.util.Slog; import com.android.server.notification.NotificationManagerService.DumpFilter; import java.io.PrintWriter; -import java.util.Date; /** Built-in zen condition provider for simple time-based conditions */ public class CountdownConditionProvider extends SystemConditionProviderService { - private static final String TAG = "ConditionProviders"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String TAG = "ConditionProviders.CCP"; + private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG); public static final ComponentName COMPONENT = new ComponentName("android", CountdownConditionProvider.class.getName()); @@ -64,7 +63,7 @@ public class CountdownConditionProvider extends SystemConditionProviderService { } @Override - public boolean isValidConditionid(Uri id) { + public boolean isValidConditionId(Uri id) { return ZenModeConfig.isValidCountdownConditionId(id); } @@ -74,6 +73,11 @@ public class CountdownConditionProvider extends SystemConditionProviderService { } @Override + public void onBootComplete() { + // noop + } + + @Override public IConditionProvider asInterface() { return (IConditionProvider) onBind(null); } @@ -170,8 +174,4 @@ public class CountdownConditionProvider extends SystemConditionProviderService { ts(time), time - now, span, ts(now)); } - private static String ts(long time) { - return new Date(time) + " (" + time + ")"; - } - } diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java new file mode 100644 index 0000000..dea6325 --- /dev/null +++ b/services/core/java/com/android/server/notification/EventConditionProvider.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2015 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.server.notification; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; +import android.service.notification.Condition; +import android.service.notification.IConditionProvider; +import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeConfig.EventInfo; +import android.util.ArraySet; +import android.util.Log; +import android.util.Slog; + +import com.android.server.notification.CalendarTracker.CheckEventResult; +import com.android.server.notification.NotificationManagerService.DumpFilter; + +import java.io.PrintWriter; + +/** + * Built-in zen condition provider for calendar event-based conditions. + */ +public class EventConditionProvider extends SystemConditionProviderService { + private static final String TAG = "ConditionProviders.ECP"; + private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG); + + public static final ComponentName COMPONENT = + new ComponentName("android", EventConditionProvider.class.getName()); + private static final String NOT_SHOWN = "..."; + private static final String SIMPLE_NAME = EventConditionProvider.class.getSimpleName(); + private static final String ACTION_EVALUATE = SIMPLE_NAME + ".EVALUATE"; + private static final int REQUEST_CODE_EVALUATE = 1; + private static final String EXTRA_TIME = "time"; + + private final Context mContext = this; + private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>(); + private final CalendarTracker mTracker = new CalendarTracker(mContext); + + private boolean mConnected; + private boolean mRegistered; + private boolean mBootComplete; // don't hammer the calendar provider until boot completes. + + public EventConditionProvider() { + if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()"); + } + + @Override + public ComponentName getComponent() { + return COMPONENT; + } + + @Override + public boolean isValidConditionId(Uri id) { + return ZenModeConfig.isValidEventConditionId(id); + } + + @Override + public void dump(PrintWriter pw, DumpFilter filter) { + pw.print(" "); pw.print(SIMPLE_NAME); pw.println(":"); + pw.print(" mConnected="); pw.println(mConnected); + pw.print(" mRegistered="); pw.println(mRegistered); + pw.print(" mBootComplete="); pw.println(mBootComplete); + pw.println(" mSubscriptions="); + for (Uri conditionId : mSubscriptions) { + pw.print(" "); + pw.println(conditionId); + } + pw.println(" mTracker="); + mTracker.dump(" ", pw); + } + + @Override + public void onBootComplete() { + if (DEBUG) Slog.d(TAG, "onBootComplete"); + if (mBootComplete) return; + mBootComplete = true; + evaluateSubscriptions(); + } + + @Override + public void onConnected() { + if (DEBUG) Slog.d(TAG, "onConnected"); + mConnected = true; + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (DEBUG) Slog.d(TAG, "onDestroy"); + mConnected = false; + } + + @Override + public void onRequestConditions(int relevance) { + if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance); + // does not advertise conditions + } + + @Override + public void onSubscribe(Uri conditionId) { + if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId); + if (!ZenModeConfig.isValidEventConditionId(conditionId)) { + notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition"); + return; + } + if (mSubscriptions.add(conditionId)) { + evaluateSubscriptions(); + } + } + + @Override + public void onUnsubscribe(Uri conditionId) { + if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId); + if (mSubscriptions.remove(conditionId)) { + evaluateSubscriptions(); + } + } + + @Override + public void attachBase(Context base) { + attachBaseContext(base); + } + + @Override + public IConditionProvider asInterface() { + return (IConditionProvider) onBind(null); + } + + private void evaluateSubscriptions() { + if (DEBUG) Log.d(TAG, "evaluateSubscriptions"); + if (!mBootComplete) { + if (DEBUG) Log.d(TAG, "Skipping evaluate before boot complete"); + return; + } + final long now = System.currentTimeMillis(); + mTracker.setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback); + setRegistered(!mSubscriptions.isEmpty()); + long reevaluateAt = 0; + for (Uri conditionId : mSubscriptions) { + final EventInfo event = ZenModeConfig.tryParseEventConditionId(conditionId); + if (event == null) { + notifyCondition(conditionId, Condition.STATE_FALSE, "badConditionId"); + continue; + } + final CheckEventResult result = mTracker.checkEvent(event, now); + if (result.recheckAt != 0 && (reevaluateAt == 0 || result.recheckAt < reevaluateAt)) { + reevaluateAt = result.recheckAt; + } + if (!result.inEvent) { + notifyCondition(conditionId, Condition.STATE_FALSE, "!inEventNow"); + continue; + } + notifyCondition(conditionId, Condition.STATE_TRUE, "inEventNow"); + } + updateAlarm(now, reevaluateAt); + if (DEBUG) Log.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now)); + } + + private void updateAlarm(long now, long time) { + final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, + REQUEST_CODE_EVALUATE, + new Intent(ACTION_EVALUATE) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) + .putExtra(EXTRA_TIME, time), + PendingIntent.FLAG_UPDATE_CURRENT); + alarms.cancel(pendingIntent); + if (time == 0 || time < now) { + if (DEBUG) Slog.d(TAG, "Not scheduling evaluate: " + (time == 0 ? "no time specified" + : "specified time in the past")); + return; + } + if (DEBUG) Slog.d(TAG, String.format("Scheduling evaluate for %s, in %s, now=%s", + ts(time), formatDuration(time - now), ts(now))); + alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent); + } + + private void notifyCondition(Uri conditionId, int state, String reason) { + if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state) + + " reason=" + reason); + notifyCondition(createCondition(conditionId, state)); + } + + private Condition createCondition(Uri id, int state) { + final String summary = NOT_SHOWN; + final String line1 = NOT_SHOWN; + final String line2 = NOT_SHOWN; + return new Condition(id, summary, line1, line2, 0, state, Condition.FLAG_RELEVANT_ALWAYS); + } + + private void setRegistered(boolean registered) { + if (mRegistered == registered) return; + if (DEBUG) Slog.d(TAG, "setRegistered " + registered); + mRegistered = registered; + if (mRegistered) { + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + filter.addAction(ACTION_EVALUATE); + registerReceiver(mReceiver, filter); + } else { + unregisterReceiver(mReceiver); + } + } + + private final CalendarTracker.Callback mTrackerCallback = new CalendarTracker.Callback() { + @Override + public void onChanged() { + if (DEBUG) Log.d(TAG, "mTrackerCallback.onChanged"); + evaluateSubscriptions(); + } + }; + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG) Slog.d(TAG, "onReceive " + intent.getAction()); + evaluateSubscriptions(); + } + }; +} diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java index 383d56c..bca13c2 100644 --- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java +++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java @@ -31,25 +31,24 @@ import android.service.notification.ZenModeConfig.ScheduleInfo; import android.util.ArraySet; import android.util.Log; import android.util.Slog; -import android.util.TimeUtils; import com.android.server.notification.NotificationManagerService.DumpFilter; import java.io.PrintWriter; -import java.util.Date; import java.util.TimeZone; /** * Built-in zen condition provider for daily scheduled time-based conditions. */ public class ScheduleConditionProvider extends SystemConditionProviderService { - private static final String TAG = "ConditionProviders"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String TAG = "ConditionProviders.SCP"; + private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG); public static final ComponentName COMPONENT = new ComponentName("android", ScheduleConditionProvider.class.getName()); private static final String NOT_SHOWN = "..."; - private static final String ACTION_EVALUATE = TAG + ".EVALUATE"; + private static final String SIMPLE_NAME = ScheduleConditionProvider.class.getSimpleName(); + private static final String ACTION_EVALUATE = SIMPLE_NAME + ".EVALUATE"; private static final int REQUEST_CODE_EVALUATE = 1; private static final String EXTRA_TIME = "time"; @@ -60,7 +59,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService { private boolean mRegistered; public ScheduleConditionProvider() { - if (DEBUG) Slog.d(TAG, "new ScheduleConditionProvider()"); + if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()"); } @Override @@ -69,13 +68,13 @@ public class ScheduleConditionProvider extends SystemConditionProviderService { } @Override - public boolean isValidConditionid(Uri id) { + public boolean isValidConditionId(Uri id) { return ZenModeConfig.isValidScheduleConditionId(id); } @Override public void dump(PrintWriter pw, DumpFilter filter) { - pw.println(" ScheduleConditionProvider:"); + pw.print(" "); pw.print(SIMPLE_NAME); pw.println(":"); pw.print(" mConnected="); pw.println(mConnected); pw.print(" mRegistered="); pw.println(mRegistered); pw.println(" mSubscriptions="); @@ -94,6 +93,11 @@ public class ScheduleConditionProvider extends SystemConditionProviderService { } @Override + public void onBootComplete() { + // noop + } + + @Override public void onDestroy() { super.onDestroy(); if (DEBUG) Slog.d(TAG, "onDestroy"); @@ -175,16 +179,6 @@ public class ScheduleConditionProvider extends SystemConditionProviderService { } } - private static String ts(long time) { - return new Date(time) + " (" + time + ")"; - } - - private static String formatDuration(long millis) { - final StringBuilder sb = new StringBuilder(); - TimeUtils.formatDuration(millis, sb); - return sb.toString(); - } - private static boolean meetsSchedule(Uri conditionId, long time) { final ScheduleCalendar cal = toScheduleCalendar(conditionId); return cal != null && cal.isInSchedule(time); diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java index a217623..8a8e063 100644 --- a/services/core/java/com/android/server/notification/SystemConditionProviderService.java +++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java @@ -21,10 +21,12 @@ import android.content.Context; import android.net.Uri; import android.service.notification.ConditionProviderService; import android.service.notification.IConditionProvider; +import android.util.TimeUtils; import com.android.server.notification.NotificationManagerService.DumpFilter; import java.io.PrintWriter; +import java.util.Date; public abstract class SystemConditionProviderService extends ConditionProviderService { @@ -32,5 +34,16 @@ public abstract class SystemConditionProviderService extends ConditionProviderSe abstract public void attachBase(Context context); abstract public IConditionProvider asInterface(); abstract public ComponentName getComponent(); - abstract public boolean isValidConditionid(Uri id); + abstract public boolean isValidConditionId(Uri id); + abstract public void onBootComplete(); + + protected static String ts(long time) { + return new Date(time) + " (" + time + ")"; + } + + protected static String formatDuration(long millis) { + final StringBuilder sb = new StringBuilder(); + TimeUtils.formatDuration(millis, sb); + return sb.toString(); + } } diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java index 766d6c5..fa314de 100644 --- a/services/core/java/com/android/server/notification/ZenModeConditions.java +++ b/services/core/java/com/android/server/notification/ZenModeConditions.java @@ -38,20 +38,19 @@ public class ZenModeConditions implements ConditionProviders.Callback { private final ConditionProviders mConditionProviders; private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>(); - private CountdownConditionProvider mCountdown; - private ScheduleConditionProvider mSchedule; private boolean mFirstEvaluation = true; public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) { mHelper = helper; mConditionProviders = conditionProviders; if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) { - mCountdown = new CountdownConditionProvider(); - mConditionProviders.addSystemProvider(mCountdown); + mConditionProviders.addSystemProvider(new CountdownConditionProvider()); } if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) { - mSchedule = new ScheduleConditionProvider(); - mConditionProviders.addSystemProvider(mSchedule); + mConditionProviders.addSystemProvider(new ScheduleConditionProvider()); + } + if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) { + mConditionProviders.addSystemProvider(new EventConditionProvider()); } mConditionProviders.setCallback(this); } @@ -128,7 +127,7 @@ public class ZenModeConditions implements ConditionProviders.Callback { final Uri id = rule.conditionId; boolean isSystemCondition = false; for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) { - if (sp.isValidConditionid(id)) { + if (sp.isValidConditionId(id)) { mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface()); rule.component = sp.getComponent(); isSystemCondition = true; diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java index 2aaeb9d..80dc523 100644 --- a/services/core/java/com/android/server/notification/ZenModeFiltering.java +++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java @@ -86,7 +86,7 @@ public class ZenModeFiltering { if (validator != null) { final float contactAffinity = validator.getContactAffinity(userHandle, extras, contactsTimeoutMs, timeoutAffinity); - return audienceMatches(config, contactAffinity); + return audienceMatches(config.allowCallsFrom, contactAffinity); } } return true; @@ -133,14 +133,14 @@ public class ZenModeFiltering { ZenLog.traceIntercepted(record, "!allowCalls"); return true; } - return shouldInterceptAudience(config, record); + return shouldInterceptAudience(config.allowCallsFrom, record); } if (isMessage(record)) { if (!config.allowMessages) { ZenLog.traceIntercepted(record, "!allowMessages"); return true; } - return shouldInterceptAudience(config, record); + return shouldInterceptAudience(config.allowMessagesFrom, record); } if (isEvent(record)) { if (!config.allowEvents) { @@ -163,9 +163,8 @@ public class ZenModeFiltering { } } - private static boolean shouldInterceptAudience(ZenModeConfig config, - NotificationRecord record) { - if (!audienceMatches(config, record.getContactAffinity())) { + private static boolean shouldInterceptAudience(int source, NotificationRecord record) { + if (!audienceMatches(source, record.getContactAffinity())) { ZenLog.traceIntercepted(record, "!audienceMatches"); return true; } @@ -219,8 +218,8 @@ public class ZenModeFiltering { return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record); } - private static boolean audienceMatches(ZenModeConfig config, float contactAffinity) { - switch (config.allowFrom) { + private static boolean audienceMatches(int source, float contactAffinity) { + switch (source) { case ZenModeConfig.SOURCE_ANYONE: return true; case ZenModeConfig.SOURCE_CONTACT: @@ -228,7 +227,7 @@ public class ZenModeFiltering { case ZenModeConfig.SOURCE_STAR: return contactAffinity >= ValidateNotificationPeople.STARRED_CONTACT; default: - Slog.w(TAG, "Encountered unknown source: " + config.allowFrom); + Slog.w(TAG, "Encountered unknown source: " + source); return true; } } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 83f0bcf..e97def8 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -209,9 +209,11 @@ public class ZenModeHelper { pw.println(config); return; } - pw.printf("allow(calls=%s,repeatCallers=%s,events=%s,from=%s,messages=%s,reminders=%s)\n", - config.allowCalls, config.allowRepeatCallers, config.allowEvents, config.allowFrom, - config.allowMessages, config.allowReminders); + pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s," + + "events=%s,reminders=%s)\n", + config.allowCalls, config.allowCallsFrom, config.allowRepeatCallers, + config.allowMessages, config.allowMessagesFrom, + config.allowEvents, config.allowReminders); pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule); if (config.automaticRules.isEmpty()) return; final int N = config.automaticRules.size(); @@ -483,8 +485,9 @@ public class ZenModeHelper { final ZenModeConfig rt = new ZenModeConfig(); rt.allowCalls = v1.allowCalls; rt.allowEvents = v1.allowEvents; - rt.allowFrom = v1.allowFrom; + rt.allowCallsFrom = v1.allowFrom; rt.allowMessages = v1.allowMessages; + rt.allowMessagesFrom = v1.allowFrom; rt.allowReminders = v1.allowReminders; // don't migrate current exit condition final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 0f3b4e6..fb98d94 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -264,9 +264,9 @@ public final class Installer extends SystemService { return mInstaller.execute(builder.toString()); } - public int moveUserDataDirs(String fromUuid, String toUuid, String packageName, int appId, - String seinfo) { - StringBuilder builder = new StringBuilder("mvuserdata"); + public int moveCompleteApp(String fromUuid, String toUuid, String packageName, + String dataAppName, int appId, String seinfo) { + StringBuilder builder = new StringBuilder("mvcompleteapp"); builder.append(' '); builder.append(escapeNull(fromUuid)); builder.append(' '); @@ -274,6 +274,8 @@ public final class Installer extends SystemService { builder.append(' '); builder.append(packageName); builder.append(' '); + builder.append(dataAppName); + builder.append(' '); builder.append(appId); builder.append(' '); builder.append(seinfo); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index a406175..09096ff 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -969,8 +969,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { public void onPackageInstalled(String basePackageName, int returnCode, String msg, Bundle extras) { if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) { + boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING); Notification notification = buildSuccessNotification(mContext, - mContext.getResources().getString(R.string.package_installed_device_owner), + mContext.getResources() + .getString(update ? R.string.package_updated_device_owner : + R.string.package_installed_device_owner), basePackageName, mUserId); if (notification != null) { @@ -980,6 +983,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName); fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageManager.installStatusToPublicStatus(returnCode)); @@ -1030,6 +1034,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { R.color.system_notification_accent_color)) .setContentTitle(packageLabel) .setContentText(contentText) + .setStyle(new Notification.BigTextStyle().bigText(contentText)) .setLargeIcon(packageIcon) .build(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 453b817..f30a5674 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -171,6 +171,7 @@ import android.util.EventLog; import android.util.ExceptionUtils; import android.util.Log; import android.util.LogPrinter; +import android.util.MathUtils; import android.util.PrintStreamPrinter; import android.util.Slog; import android.util.SparseArray; @@ -241,6 +242,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -274,8 +277,6 @@ public class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_DEXOPT = false; private static final boolean DEBUG_ABI_SELECTION = false; - static final boolean RUNTIME_PERMISSIONS_ENABLED = true; - private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; @@ -299,7 +300,6 @@ public class PackageManagerService extends IPackageManager.Stub { static final int SCAN_BOOTING = 1<<8; static final int SCAN_TRUSTED_OVERLAY = 1<<9; static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10; - static final int SCAN_REPLACING = 1<<11; static final int SCAN_REQUIRE_KNOWN = 1<<12; static final int REMOVE_CHATTY = 1<<16; @@ -1603,6 +1603,12 @@ public class PackageManagerService extends IPackageManager.Stub { res.origPackage); break; } + case PackageManager.INSTALL_SUCCEEDED: { + extras = new Bundle(); + extras.putBoolean(Intent.EXTRA_REPLACING, + res.removedInfo != null && res.removedInfo.removedPackage != null); + break; + } } return extras; } @@ -2123,13 +2129,6 @@ public class PackageManagerService extends IPackageManager.Stub { + "; regranting permissions for internal storage"); mSettings.mInternalSdkPlatform = mSdkVersion; - // For now runtime permissions are toggled via a system property. - if (!RUNTIME_PERMISSIONS_ENABLED) { - // Remove the runtime permissions state if the feature - // was disabled by flipping the system property. - mSettings.deleteRuntimePermissionsFiles(); - } - updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) @@ -2153,6 +2152,9 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.mFingerprint = Build.FINGERPRINT; } + primeDomainVerificationsLPw(false); + checkDefaultBrowser(); + // All the changes are done during package scanning. mSettings.updateInternalDatabaseVersion(); @@ -2170,8 +2172,6 @@ public class PackageManagerService extends IPackageManager.Stub { mIntentFilterVerifier = new IntentVerifierProxy(mContext, mIntentFilterVerifierComponent); - primeDomainVerificationsLPw(false); - } // synchronized (mPackages) } // synchronized (mInstallLock) @@ -2269,9 +2269,9 @@ public class PackageManagerService extends IPackageManager.Stub { } private void primeDomainVerificationsLPw(boolean logging) { - Slog.d(TAG, "Start priming domain verification"); + Slog.d(TAG, "Start priming domain verifications"); boolean updated = false; - ArrayList<String> allHosts = new ArrayList<>(); + ArraySet<String> allHostsSet = new ArraySet<>(); for (PackageParser.Package pkg : mPackages.values()) { final String packageName = pkg.packageName; if (!hasDomainURLs(pkg)) { @@ -2291,18 +2291,20 @@ public class PackageManagerService extends IPackageManager.Stub { for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { if (hasValidDomains(filter, false)) { - allHosts.addAll(filter.getHostsList()); + allHostsSet.addAll(filter.getHostsList()); } } } - if (allHosts.size() == 0) { - allHosts.add("*"); + if (allHostsSet.size() == 0) { + allHostsSet.add("*"); } + ArrayList<String> allHostsList = new ArrayList<>(allHostsSet); IntentFilterVerificationInfo ivi = - mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHosts); + mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHostsList); if (ivi != null) { // We will always log this - Slog.d(TAG, "Priming domain verifications for package: " + packageName); + Slog.d(TAG, "Priming domain verifications for package: " + packageName + + " with hosts:" + ivi.getDomainsString()); ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS); updated = true; } @@ -2311,12 +2313,25 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.d(TAG, "No priming domain verifications for package: " + packageName); } } - allHosts.clear(); + allHostsSet.clear(); } if (updated) { - scheduleWriteSettingsLocked(); + if (logging) { + Slog.d(TAG, "Will need to write primed domain verifications"); + } + } + Slog.d(TAG, "End priming domain verifications"); + } + + private void checkDefaultBrowser() { + final int myUserId = UserHandle.myUserId(); + final String packageName = getDefaultBrowserPackageName(myUserId); + PackageInfo info = getPackageInfo(packageName, 0, myUserId); + if (info == null) { + Slog.w(TAG, "Clearing default Browser as its package is no more installed: " + + packageName); + setDefaultBrowserPackageName(null, myUserId); } - Slog.d(TAG, "End priming domain verification"); } @Override @@ -2380,6 +2395,18 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + public boolean isPackageFrozen(String packageName) { + synchronized (mPackages) { + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + return ps.frozen; + } + } + Slog.w(TAG, "Package " + packageName + " is missing; assuming frozen"); + return true; + } + + @Override public boolean isPackageAvailable(String packageName, int userId) { if (!sUserManager.exists(userId)) return false; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "is package available"); @@ -3113,13 +3140,9 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public boolean grantPermission(String packageName, String name, int userId) { - if (!RUNTIME_PERMISSIONS_ENABLED) { - return false; - } - + public void grantPermission(String packageName, String name, int userId) { if (!sUserManager.exists(userId)) { - return false; + return; } mContext.enforceCallingOrSelfPermission( @@ -3155,12 +3178,13 @@ public class PackageManagerService extends IPackageManager.Stub { final int result = permissionsState.grantRuntimePermission(bp, userId); switch (result) { case PermissionsState.PERMISSION_OPERATION_FAILURE: { - return false; + return; } case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { gidsChanged = true; - } break; + } + break; } // Not critical if that is lost - app has to request again. @@ -3170,18 +3194,12 @@ public class PackageManagerService extends IPackageManager.Stub { if (gidsChanged) { killSettingPackagesForUser(sb, userId, KILL_APP_REASON_GIDS_CHANGED); } - - return true; } @Override - public boolean revokePermission(String packageName, String name, int userId) { - if (!RUNTIME_PERMISSIONS_ENABLED) { - return false; - } - + public void revokePermission(String packageName, String name, int userId) { if (!sUserManager.exists(userId)) { - return false; + return; } mContext.enforceCallingOrSelfPermission( @@ -3215,7 +3233,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (permissionsState.revokeRuntimePermission(bp, userId) == PermissionsState.PERMISSION_OPERATION_FAILURE) { - return false; + return; } // Critical, after this call all should never have the permission. @@ -3223,8 +3241,6 @@ public class PackageManagerService extends IPackageManager.Stub { } killSettingPackagesForUser(sb, userId, KILL_APP_REASON_PERMISSIONS_REVOKED); - - return true; } @Override @@ -5032,8 +5048,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), - ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, - getAppDexInstructionSets(ps)); + ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } @@ -5099,8 +5114,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), - ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, - getAppDexInstructionSets(ps)); + ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } @@ -6482,14 +6496,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } - // Request the ActivityManager to kill the process(only for existing packages) - // so that we do not end up in a confused state while the user is still using the older - // version of the application while the new one gets installed. - if ((scanFlags & SCAN_REPLACING) != 0) { - killApplication(pkg.applicationInfo.packageName, - pkg.applicationInfo.uid, "update pkg"); - } - // Also need to kill any apps that are dependent on the library. if (clientLibPkgs != null) { for (int i=0; i<clientLibPkgs.size(); i++) { @@ -7578,9 +7584,7 @@ public class PackageManagerService extends IPackageManager.Stub { } break; case PermissionInfo.PROTECTION_DANGEROUS: { - if (!RUNTIME_PERMISSIONS_ENABLED - || pkg.applicationInfo.targetSdkVersion - <= Build.VERSION_CODES.LOLLIPOP_MR1) { + if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) { // For legacy apps dangerous permissions are install time ones. grant = GRANT_INSTALL; } else if (ps.isSystem()) { @@ -7719,10 +7723,8 @@ public class PackageManagerService extends IPackageManager.Stub { ps.setPermissionsUpdatedForUserIds(currentUserIds); // Persist the runtime permissions state for users with changes. - if (RUNTIME_PERMISSIONS_ENABLED) { - for (int userId : changedRuntimePermissionUserIds) { - mSettings.writeRuntimePermissionsForUserLPr(userId, true); - } + for (int userId : changedRuntimePermissionUserIds) { + mSettings.writeRuntimePermissionsForUserLPr(userId, true); } } @@ -8490,46 +8492,53 @@ public class PackageManagerService extends IPackageManager.Stub { } }; - static final void sendPackageBroadcast(String action, String pkg, - Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, - int[] userIds) { - IActivityManager am = ActivityManagerNative.getDefault(); - if (am != null) { - try { - if (userIds == null) { - userIds = am.getRunningUserIds(); - } - for (int id : userIds) { - final Intent intent = new Intent(action, - pkg != null ? Uri.fromParts("package", pkg, null) : null); - if (extras != null) { - intent.putExtras(extras); - } - if (targetPkg != null) { - intent.setPackage(targetPkg); - } - // Modify the UID when posting to other users - int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); - if (uid > 0 && UserHandle.getUserId(uid) != id) { - uid = UserHandle.getUid(id, UserHandle.getAppId(uid)); - intent.putExtra(Intent.EXTRA_UID, uid); + final void sendPackageBroadcast(final String action, final String pkg, + final Bundle extras, final String targetPkg, final IIntentReceiver finishedReceiver, + final int[] userIds) { + mHandler.post(new Runnable() { + @Override + public void run() { + try { + final IActivityManager am = ActivityManagerNative.getDefault(); + if (am == null) return; + final int[] resolvedUserIds; + if (userIds == null) { + resolvedUserIds = am.getRunningUserIds(); + } else { + resolvedUserIds = userIds; } - intent.putExtra(Intent.EXTRA_USER_HANDLE, id); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (DEBUG_BROADCASTS) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.d(TAG, "Sending to user " + id + ": " - + intent.toShortString(false, true, false, false) - + " " + intent.getExtras(), here); + for (int id : resolvedUserIds) { + final Intent intent = new Intent(action, + pkg != null ? Uri.fromParts("package", pkg, null) : null); + if (extras != null) { + intent.putExtras(extras); + } + if (targetPkg != null) { + intent.setPackage(targetPkg); + } + // Modify the UID when posting to other users + int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + if (uid > 0 && UserHandle.getUserId(uid) != id) { + uid = UserHandle.getUid(id, UserHandle.getAppId(uid)); + intent.putExtra(Intent.EXTRA_UID, uid); + } + intent.putExtra(Intent.EXTRA_USER_HANDLE, id); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (DEBUG_BROADCASTS) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.d(TAG, "Sending to user " + id + ": " + + intent.toShortString(false, true, false, false) + + " " + intent.getExtras(), here); + } + am.broadcastIntent(null, intent, null, finishedReceiver, + 0, null, null, null, android.app.AppOpsManager.OP_NONE, + finishedReceiver != null, false, id); } - am.broadcastIntent(null, intent, null, finishedReceiver, - 0, null, null, null, android.app.AppOpsManager.OP_NONE, - finishedReceiver != null, false, id); + } catch (RemoteException ex) { } - } catch (RemoteException ex) { } - } + }); } /** @@ -8656,8 +8665,8 @@ public class PackageManagerService extends IPackageManager.Stub { final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile); final Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(origin, observer, installFlags, - installerPackageName, null, verificationParams, user, packageAbiOverride); + msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName, + null, verificationParams, user, packageAbiOverride); mHandler.sendMessage(msg); } @@ -8675,7 +8684,7 @@ public class PackageManagerService extends IPackageManager.Stub { } final Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(origin, observer, params.installFlags, + msg.obj = new InstallParams(origin, null, observer, params.installFlags, installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride); mHandler.sendMessage(msg); } @@ -9128,7 +9137,11 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean setDefaultBrowserPackageName(String packageName, int userId) { synchronized (mPackages) { - return mSettings.setDefaultBrowserPackageNameLPr(packageName, userId); + boolean result = mSettings.setDefaultBrowserPackageNameLPr(packageName, userId); + result |= updateIntentVerificationStatus(packageName, + PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, + UserHandle.myUserId()); + return result; } } @@ -9508,8 +9521,30 @@ public class PackageManagerService extends IPackageManager.Stub { } } + class MoveInfo { + final int moveId; + final String fromUuid; + final String toUuid; + final String packageName; + final String dataAppName; + final int appId; + final String seinfo; + + public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName, + String dataAppName, int appId, String seinfo) { + this.moveId = moveId; + this.fromUuid = fromUuid; + this.toUuid = toUuid; + this.packageName = packageName; + this.dataAppName = dataAppName; + this.appId = appId; + this.seinfo = seinfo; + } + } + class InstallParams extends HandlerParams { final OriginInfo origin; + final MoveInfo move; final IPackageInstallObserver2 observer; int installFlags; final String installerPackageName; @@ -9519,11 +9554,12 @@ public class PackageManagerService extends IPackageManager.Stub { private int mRet; final String packageAbiOverride; - InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags, - String installerPackageName, String volumeUuid, + InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, + int installFlags, String installerPackageName, String volumeUuid, VerificationParams verificationParams, UserHandle user, String packageAbiOverride) { super(user); this.origin = origin; + this.move = move; this.observer = observer; this.installFlags = installFlags; this.installerPackageName = installerPackageName; @@ -9902,7 +9938,9 @@ public class PackageManagerService extends IPackageManager.Stub { } private InstallArgs createInstallArgs(InstallParams params) { - if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) { + if (params.move != null) { + return new MoveInstallArgs(params); + } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) { return new AsecInstallArgs(params); } else { return new FileInstallArgs(params); @@ -9914,7 +9952,7 @@ public class PackageManagerService extends IPackageManager.Stub { * when cleaning up old installs, or used as a move source. */ private InstallArgs createInstallArgsForExisting(int installFlags, String codePath, - String resourcePath, String nativeLibraryRoot, String[] instructionSets) { + String resourcePath, String[] instructionSets) { final boolean isInAsec; if (installOnExternalAsec(installFlags)) { /* Apps on SD card are always in ASEC containers. */ @@ -9934,14 +9972,15 @@ public class PackageManagerService extends IPackageManager.Stub { return new AsecInstallArgs(codePath, instructionSets, installOnExternalAsec(installFlags), installForwardLocked(installFlags)); } else { - return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot, - instructionSets); + return new FileInstallArgs(codePath, resourcePath, instructionSets); } } static abstract class InstallArgs { /** @see InstallParams#origin */ final OriginInfo origin; + /** @see InstallParams#move */ + final MoveInfo move; final IPackageInstallObserver2 observer; // Always refers to PackageManager flags only @@ -9957,10 +9996,12 @@ public class PackageManagerService extends IPackageManager.Stub { // if we move dex files under the common app path. /* nullable */ String[] instructionSets; - InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags, - String installerPackageName, String volumeUuid, ManifestDigest manifestDigest, - UserHandle user, String[] instructionSets, String abiOverride) { + InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, + int installFlags, String installerPackageName, String volumeUuid, + ManifestDigest manifestDigest, UserHandle user, String[] instructionSets, + String abiOverride) { this.origin = origin; + this.move = move; this.installFlags = installFlags; this.observer = observer; this.installerPackageName = installerPackageName; @@ -9985,12 +10026,10 @@ public class PackageManagerService extends IPackageManager.Stub { abstract String getCodePath(); /** @see PackageSettingBase#resourcePathString */ abstract String getResourcePath(); - abstract String getLegacyNativeLibraryPath(); // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); abstract boolean doPostDeleteLI(boolean delete); - abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException; /** * Called before the source arguments are copied. This is used mostly @@ -10051,7 +10090,6 @@ public class PackageManagerService extends IPackageManager.Stub { class FileInstallArgs extends InstallArgs { private File codeFile; private File resourceFile; - private File legacyNativeLibraryPath; // Example topology: // /data/app/com.example/base.apk @@ -10062,7 +10100,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install */ FileInstallArgs(InstallParams params) { - super(params.origin, params.observer, params.installFlags, + super(params.origin, params.move, params.observer, params.installFlags, params.installerPackageName, params.volumeUuid, params.getManifestDigest(), params.getUser(), null /* instruction sets */, params.packageAbiOverride); if (isFwdLocked()) { @@ -10071,21 +10109,11 @@ public class PackageManagerService extends IPackageManager.Stub { } /** Existing install */ - FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath, - String[] instructionSets) { - super(OriginInfo.fromNothing(), null, 0, null, null, null, null, instructionSets, null); + FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) { + super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets, + null); this.codeFile = (codePath != null) ? new File(codePath) : null; this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; - this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ? - new File(legacyNativeLibraryPath) : null; - } - - boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { - final long sizeBytes = imcs.calculateInstalledSize(origin.file.getAbsolutePath(), - isFwdLocked(), abiOverride); - - final StorageManager storage = StorageManager.from(mContext); - return (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory())); } int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { @@ -10157,46 +10185,46 @@ public class PackageManagerService extends IPackageManager.Stub { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); return false; - } else { - final File targetDir = codeFile.getParentFile(); - final File beforeCodeFile = codeFile; - final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName); + } - Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); - try { - Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); - } catch (ErrnoException e) { - Slog.d(TAG, "Failed to rename", e); - return false; - } + final File targetDir = codeFile.getParentFile(); + final File beforeCodeFile = codeFile; + final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName); - if (!SELinux.restoreconRecursive(afterCodeFile)) { - Slog.d(TAG, "Failed to restorecon"); - return false; - } + Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); + try { + Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath()); + } catch (ErrnoException e) { + Slog.d(TAG, "Failed to rename", e); + return false; + } + + if (!SELinux.restoreconRecursive(afterCodeFile)) { + Slog.d(TAG, "Failed to restorecon"); + return false; + } - // Reflect the rename internally - codeFile = afterCodeFile; - resourceFile = afterCodeFile; + // Reflect the rename internally + codeFile = afterCodeFile; + resourceFile = afterCodeFile; - // Reflect the rename in scanned details - pkg.codePath = afterCodeFile.getAbsolutePath(); - pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, - pkg.baseCodePath); - pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, - pkg.splitCodePaths); + // Reflect the rename in scanned details + pkg.codePath = afterCodeFile.getAbsolutePath(); + pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, + pkg.baseCodePath); + pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, + pkg.splitCodePaths); - // Reflect the rename in app info - pkg.applicationInfo.volumeUuid = pkg.volumeUuid; - pkg.applicationInfo.setCodePath(pkg.codePath); - pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath); - pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths); - pkg.applicationInfo.setResourcePath(pkg.codePath); - pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath); - pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths); + // Reflect the rename in app info + pkg.applicationInfo.volumeUuid = pkg.volumeUuid; + pkg.applicationInfo.setCodePath(pkg.codePath); + pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath); + pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths); + pkg.applicationInfo.setResourcePath(pkg.codePath); + pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath); + pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths); - return true; - } + return true; } int doPostInstall(int status, int uid) { @@ -10216,11 +10244,6 @@ public class PackageManagerService extends IPackageManager.Stub { return (resourceFile != null) ? resourceFile.getAbsolutePath() : null; } - @Override - String getLegacyNativeLibraryPath() { - return (legacyNativeLibraryPath != null) ? legacyNativeLibraryPath.getAbsolutePath() : null; - } - private boolean cleanUp() { if (codeFile == null || !codeFile.exists()) { return false; @@ -10236,13 +10259,6 @@ public class PackageManagerService extends IPackageManager.Stub { resourceFile.delete(); } - if (legacyNativeLibraryPath != null && !FileUtils.contains(codeFile, legacyNativeLibraryPath)) { - if (!FileUtils.deleteContents(legacyNativeLibraryPath)) { - Slog.w(TAG, "Couldn't delete native library directory " + legacyNativeLibraryPath); - } - legacyNativeLibraryPath.delete(); - } - return true; } @@ -10306,11 +10322,10 @@ public class PackageManagerService extends IPackageManager.Stub { String cid; String packagePath; String resourcePath; - String legacyNativeLibraryDir; /** New install */ AsecInstallArgs(InstallParams params) { - super(params.origin, params.observer, params.installFlags, + super(params.origin, params.move, params.observer, params.installFlags, params.installerPackageName, params.volumeUuid, params.getManifestDigest(), params.getUser(), null /* instruction sets */, params.packageAbiOverride); } @@ -10318,7 +10333,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** Existing install */ AsecInstallArgs(String fullCodePath, String[] instructionSets, boolean isExternal, boolean isForwardLocked) { - super(OriginInfo.fromNothing(), null, (isExternal ? INSTALL_EXTERNAL : 0) + super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0) | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null, instructionSets, null); // Hackily pretend we're still looking at a full code path @@ -10335,7 +10350,7 @@ public class PackageManagerService extends IPackageManager.Stub { } AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) { - super(OriginInfo.fromNothing(), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0) + super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0) | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null, instructionSets, null); this.cid = cid; @@ -10346,21 +10361,6 @@ public class PackageManagerService extends IPackageManager.Stub { cid = mInstallerService.allocateExternalStageCidLegacy(); } - boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { - final long sizeBytes = imcs.calculateInstalledSize(packagePath, isFwdLocked(), - abiOverride); - - final File target; - if (isExternalAsec()) { - target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory(); - } else { - target = Environment.getDataDirectory(); - } - - final StorageManager storage = StorageManager.from(mContext); - return (sizeBytes <= storage.getStorageBytesUntilLow(target)); - } - int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { if (origin.staged) { Slog.d(TAG, origin.cid + " already staged; skipping copy"); @@ -10401,11 +10401,6 @@ public class PackageManagerService extends IPackageManager.Stub { return resourcePath; } - @Override - String getLegacyNativeLibraryPath() { - return legacyNativeLibraryDir; - } - int doPreInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { // Destroy container @@ -10504,8 +10499,6 @@ public class PackageManagerService extends IPackageManager.Stub { packagePath = mountFile.getAbsolutePath(); resourcePath = packagePath; } - - legacyNativeLibraryDir = new File(mountFile, LIB_DIR_NAME).getAbsolutePath(); } int doPostInstall(int status, int uid) { @@ -10567,8 +10560,6 @@ public class PackageManagerService extends IPackageManager.Stub { removeDexFiles(allCodePaths, instructionSets); } - - String getPackageName() { return getAsecPackageName(cid); } @@ -10617,6 +10608,108 @@ public class PackageManagerService extends IPackageManager.Stub { } } + /** + * Logic to handle movement of existing installed applications. + */ + class MoveInstallArgs extends InstallArgs { + private File codeFile; + private File resourceFile; + + /** New install */ + MoveInstallArgs(InstallParams params) { + super(params.origin, params.move, params.observer, params.installFlags, + params.installerPackageName, params.volumeUuid, params.getManifestDigest(), + params.getUser(), null /* instruction sets */, params.packageAbiOverride); + } + + int copyApk(IMediaContainerService imcs, boolean temp) { + Slog.d(TAG, "Moving " + move.packageName + " from " + move.fromUuid + " to " + + move.toUuid); + synchronized (mInstaller) { + if (mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName, + move.dataAppName, move.appId, move.seinfo) != 0) { + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + } + } + + codeFile = new File(Environment.getDataAppDirectory(move.toUuid), move.dataAppName); + resourceFile = codeFile; + Slog.d(TAG, "codeFile after move is " + codeFile); + + return PackageManager.INSTALL_SUCCEEDED; + } + + int doPreInstall(int status) { + if (status != PackageManager.INSTALL_SUCCEEDED) { + cleanUp(); + } + return status; + } + + boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) { + if (status != PackageManager.INSTALL_SUCCEEDED) { + cleanUp(); + return false; + } + + // Reflect the move in app info + pkg.applicationInfo.volumeUuid = pkg.volumeUuid; + pkg.applicationInfo.setCodePath(pkg.codePath); + pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath); + pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths); + pkg.applicationInfo.setResourcePath(pkg.codePath); + pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath); + pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths); + + return true; + } + + int doPostInstall(int status, int uid) { + if (status != PackageManager.INSTALL_SUCCEEDED) { + cleanUp(); + } + return status; + } + + @Override + String getCodePath() { + return (codeFile != null) ? codeFile.getAbsolutePath() : null; + } + + @Override + String getResourcePath() { + return (resourceFile != null) ? resourceFile.getAbsolutePath() : null; + } + + private boolean cleanUp() { + if (codeFile == null || !codeFile.exists()) { + return false; + } + + if (codeFile.isDirectory()) { + mInstaller.rmPackageDir(codeFile.getAbsolutePath()); + } else { + codeFile.delete(); + } + + if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) { + resourceFile.delete(); + } + + return true; + } + + void cleanUpResourcesLI() { + cleanUp(); + } + + boolean doPostDeleteLI(boolean delete) { + // XXX err, shouldn't we respect the delete flag? + cleanUpResourcesLI(); + return true; + } + } + static String getAsecPackageName(String packageCid) { int idx = packageCid.lastIndexOf("-"); if (idx == -1) { @@ -10797,16 +10890,17 @@ public class PackageManagerService extends IPackageManager.Stub { private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user, String installerPackageName, String volumeUuid, PackageInstalledInfo res) { - PackageParser.Package oldPackage; - String pkgName = pkg.packageName; - int[] allUsers; - boolean[] perUserInstalled; + final PackageParser.Package oldPackage; + final String pkgName = pkg.packageName; + final int[] allUsers; + final boolean[] perUserInstalled; + final boolean weFroze; // First find the old package info and check signatures synchronized(mPackages) { oldPackage = mPackages.get(pkgName); if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage); - PackageSetting ps = mSettings.mPackages.get(pkgName); + final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps == null || !ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) { // default to original signature matching if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures) @@ -10830,15 +10924,35 @@ public class PackageManagerService extends IPackageManager.Stub { for (int i = 0; i < allUsers.length; i++) { perUserInstalled[i] = ps != null ? ps.getInstalled(allUsers[i]) : false; } + + // Mark the app as frozen to prevent launching during the upgrade + // process, and then kill all running instances + if (!ps.frozen) { + ps.frozen = true; + weFroze = true; + } else { + weFroze = false; + } } - boolean sysPkg = (isSystemApp(oldPackage)); - if (sysPkg) { - replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags, - user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res); - } else { - replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags, - user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res); + // Now that we're guarded by frozen state, kill app during upgrade + killApplication(pkgName, oldPackage.applicationInfo.uid, "replace pkg"); + + try { + boolean sysPkg = (isSystemApp(oldPackage)); + if (sysPkg) { + replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags, + user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res); + } else { + replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags, + user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res); + } + } finally { + // Regardless of success or failure of upgrade steps above, always + // unfreeze the package if we froze it + if (weFroze) { + unfreezePackage(pkgName); + } } } @@ -10968,8 +11082,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } - killApplication(packageName, oldPkg.applicationInfo.uid, "replace sys pkg"); - res.removedInfo.uid = oldPkg.applicationInfo.uid; res.removedInfo.removedPackage = packageName; // Remove existing system package @@ -10984,7 +11096,6 @@ public class PackageManagerService extends IPackageManager.Stub { res.removedInfo.args = createInstallArgsForExisting(0, deletedPackage.applicationInfo.getCodePath(), deletedPackage.applicationInfo.getResourcePath(), - deletedPackage.applicationInfo.nativeLibraryRootDir, getAppDexInstructionSets(deletedPackage.applicationInfo)); } else { res.removedInfo.args = null; @@ -11292,8 +11403,10 @@ public class PackageManagerService extends IPackageManager.Stub { return; } - // If app directory is not writable, dexopt will be called after the rename - if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) { + if (args.move != null) { + // We did an in-place move, so dex is ready to roll + scanFlags |= SCAN_NO_DEX; + } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) { // Enable SCAN_NO_DEX flag to skip dexopt at a later stage scanFlags |= SCAN_NO_DEX; // Run dexopt before old package gets removed, to minimize time when app is unavailable @@ -11314,7 +11427,7 @@ public class PackageManagerService extends IPackageManager.Stub { startIntentFilterVerifications(args.user.getIdentifier(), pkg); if (replace) { - replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, + replacePackageLI(pkg, parseFlags, scanFlags, args.user, installerPackageName, volumeUuid, res); } else { installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, @@ -11676,7 +11789,7 @@ public class PackageManagerService extends IPackageManager.Stub { return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; } - static class PackageRemovedInfo { + class PackageRemovedInfo { String removedPackage; int uid = -1; int removedAppId = -1; @@ -11921,8 +12034,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Delete application code and resources if (deleteCodeAndResources && (outInfo != null)) { outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), - ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, - getAppDexInstructionSets(ps)); + ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps)); if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); } return true; @@ -13091,8 +13203,8 @@ public class PackageManagerService extends IPackageManager.Stub { enforceCrossUserPermission(uid, userId, true, true, "stop package"); // writer synchronized (mPackages) { - if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission, - uid, userId)) { + if (mSettings.setPackageStoppedStateLPw(this, packageName, stopped, + allowedByPermission, uid, userId)) { scheduleWritePackageRestrictionsLocked(userId); } } @@ -14152,17 +14264,16 @@ public class PackageManagerService extends IPackageManager.Stub { private void loadPrivatePackages(VolumeInfo vol) { final ArrayList<ApplicationInfo> loaded = new ArrayList<>(); final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE; + synchronized (mInstallLock) { synchronized (mPackages) { final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid); for (PackageSetting ps : packages) { - synchronized (mInstallLock) { - final PackageParser.Package pkg; - try { - pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null); - loaded.add(pkg.applicationInfo); - } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); - } + final PackageParser.Package pkg; + try { + pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null); + loaded.add(pkg.applicationInfo); + } catch (PackageManagerException e) { + Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); } } @@ -14170,6 +14281,7 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.writeLPr(); } + } Slog.d(TAG, "Loaded packages " + loaded); sendResourcesChangedBroadcast(true, false, loaded, null); @@ -14177,29 +14289,39 @@ public class PackageManagerService extends IPackageManager.Stub { private void unloadPrivatePackages(VolumeInfo vol) { final ArrayList<ApplicationInfo> unloaded = new ArrayList<>(); + synchronized (mInstallLock) { synchronized (mPackages) { final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid); for (PackageSetting ps : packages) { if (ps.pkg == null) continue; - synchronized (mInstallLock) { - final ApplicationInfo info = ps.pkg.applicationInfo; - final PackageRemovedInfo outInfo = new PackageRemovedInfo(); - if (deletePackageLI(ps.name, null, false, null, null, - PackageManager.DELETE_KEEP_DATA, outInfo, false)) { - unloaded.add(info); - } else { - Slog.w(TAG, "Failed to unload " + ps.codePath); - } + + final ApplicationInfo info = ps.pkg.applicationInfo; + final PackageRemovedInfo outInfo = new PackageRemovedInfo(); + if (deletePackageLI(ps.name, null, false, null, null, + PackageManager.DELETE_KEEP_DATA, outInfo, false)) { + unloaded.add(info); + } else { + Slog.w(TAG, "Failed to unload " + ps.codePath); } } mSettings.writeLPr(); } + } Slog.d(TAG, "Unloaded packages " + unloaded); sendResourcesChangedBroadcast(false, false, unloaded, null); } + private void unfreezePackage(String packageName) { + synchronized (mPackages) { + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + ps.frozen = false; + } + } + } + @Override public int movePackage(final String packageName, final String volumeUuid) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); @@ -14218,6 +14340,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void movePackageInternal(final String packageName, final String volumeUuid, final int moveId) throws PackageManagerException { final UserHandle user = new UserHandle(UserHandle.getCallingUserId()); + final StorageManager storage = mContext.getSystemService(StorageManager.class); final PackageManager pm = mContext.getPackageManager(); final boolean currentAsec; @@ -14240,14 +14363,25 @@ public class PackageManagerService extends IPackageManager.Stub { if (pkg.applicationInfo.isSystemApp()) { throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, "Cannot move system application"); - } else if (pkg.mOperationPending) { - throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING, - "Attempt to move package which has pending operations"); } - // TODO: yell if already in desired location + if (Objects.equals(ps.volumeUuid, volumeUuid)) { + throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, + "Package already moved to " + volumeUuid); + } - pkg.mOperationPending = true; + final File probe = new File(pkg.codePath); + final File probeOat = new File(probe, "oat"); + if (!probe.isDirectory() || !probeOat.isDirectory()) { + throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, + "Move only supported for modern cluster style installs"); + } + + if (ps.frozen) { + throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING, + "Failed to move already frozen package"); + } + ps.frozen = true; currentAsec = pkg.applicationInfo.isForwardLocked() || pkg.applicationInfo.isExternalAsec(); @@ -14260,25 +14394,31 @@ public class PackageManagerService extends IPackageManager.Stub { label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)); } + // Now that we're guarded by frozen state, kill app during move + killApplication(packageName, appId, "move pkg"); + final Bundle extras = new Bundle(); extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName); extras.putString(Intent.EXTRA_TITLE, label); mMoveCallbacks.notifyCreated(moveId, extras); int installFlags; - final boolean moveData; + final boolean moveCompleteApp; + final File measurePath; if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { installFlags = INSTALL_INTERNAL; - moveData = !currentAsec; + moveCompleteApp = !currentAsec; + measurePath = Environment.getDataAppDirectory(volumeUuid); } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { installFlags = INSTALL_EXTERNAL; - moveData = false; + moveCompleteApp = false; + measurePath = storage.getPrimaryPhysicalVolume().getPath(); } else { - final StorageManager storage = mContext.getSystemService(StorageManager.class); final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid); if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE || !volume.isMountedWritable()) { + unfreezePackage(packageName); throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Move location not mounted private volume"); } @@ -14286,32 +14426,38 @@ public class PackageManagerService extends IPackageManager.Stub { Preconditions.checkState(!currentAsec); installFlags = INSTALL_INTERNAL; - moveData = true; + moveCompleteApp = true; + measurePath = Environment.getDataAppDirectory(volumeUuid); } - Slog.d(TAG, "Moving " + packageName + " from " + currentVolumeUuid + " to " + volumeUuid); - mMoveCallbacks.notifyStatusChanged(moveId, 10); + final PackageStats stats = new PackageStats(null, -1); + synchronized (mInstaller) { + if (!getPackageSizeInfoLI(packageName, -1, stats)) { + unfreezePackage(packageName); + throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, + "Failed to measure package size"); + } + } - if (moveData) { - synchronized (mInstallLock) { - // TODO: split this into separate copy and delete operations - if (mInstaller.moveUserDataDirs(currentVolumeUuid, volumeUuid, packageName, appId, - seinfo) != 0) { - synchronized (mPackages) { - final PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null) { - pkg.mOperationPending = false; - } - } + Slog.d(TAG, "Measured code size " + stats.codeSize + ", data size " + stats.dataSize); - throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, - "Failed to move private data"); - } - } + final long startFreeBytes = measurePath.getFreeSpace(); + final long sizeBytes; + if (moveCompleteApp) { + sizeBytes = stats.codeSize + stats.dataSize; + } else { + sizeBytes = stats.codeSize; + } + + if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) { + unfreezePackage(packageName); + throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, + "Not enough free space to move"); } - mMoveCallbacks.notifyStatusChanged(moveId, 50); + mMoveCallbacks.notifyStatusChanged(moveId, 10); + final CountDownLatch installedLatch = new CountDownLatch(1); final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() { @Override public void onUserActionRequired(Intent intent) throws RemoteException { @@ -14324,15 +14470,11 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.d(TAG, "Install result for move: " + PackageManager.installStatusToString(returnCode, msg)); - // We usually have a new package now after the install, but if - // we failed we need to clear the pending flag on the original - // package object. - synchronized (mPackages) { - final PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null) { - pkg.mOperationPending = false; - } - } + installedLatch.countDown(); + + // Regardless of success or failure of the move operation, + // always unfreeze the package + unfreezePackage(packageName); final int status = PackageManager.installStatusToPublicStatus(returnCode); switch (status) { @@ -14352,13 +14494,40 @@ public class PackageManagerService extends IPackageManager.Stub { } }; - // Treat a move like reinstalling an existing app, which ensures that we - // process everythign uniformly, like unpacking native libraries. + final MoveInfo move; + if (moveCompleteApp) { + // Kick off a thread to report progress estimates + new Thread() { + @Override + public void run() { + while (true) { + try { + if (installedLatch.await(1, TimeUnit.SECONDS)) { + break; + } + } catch (InterruptedException ignored) { + } + + final long deltaFreeBytes = startFreeBytes - measurePath.getFreeSpace(); + final int progress = 10 + (int) MathUtils.constrain( + ((deltaFreeBytes * 80) / sizeBytes), 0, 80); + mMoveCallbacks.notifyStatusChanged(moveId, progress); + } + } + }.start(); + + final String dataAppName = codeFile.getName(); + move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName, + dataAppName, appId, seinfo); + } else { + move = null; + } + installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; final Message msg = mHandler.obtainMessage(INIT_COPY); final OriginInfo origin = OriginInfo.fromExistingFile(codeFile); - msg.obj = new InstallParams(origin, installObserver, installFlags, + msg.obj = new InstallParams(origin, move, installObserver, installFlags, installerPackageName, volumeUuid, null, user, packageAbiOverride); mHandler.sendMessage(msg); } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 5429517..f62c00c 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -108,6 +108,13 @@ abstract class PackageSettingBase extends SettingBase { int installStatus = PKG_INSTALL_COMPLETE; + /** + * Non-persisted value indicating this package has been temporarily frozen, + * usually during a critical section of the package update pipeline. The + * platform will refuse to launch packages in a frozen state. + */ + boolean frozen = false; + PackageSettingBase origPackage; /** Package name of the app that installed this package */ diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 252c16a..d476bfde 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -985,6 +985,13 @@ final class Settings { if (ivi == null) { ivi = new IntentFilterVerificationInfo(packageName, domains); ps.setIntentFilterVerificationInfo(ivi); + Slog.d(PackageManagerService.TAG, + "Creating new IntentFilterVerificationInfo for packageName: " + packageName); + } else { + ivi.setDomains(domains); + Slog.d(PackageManagerService.TAG, + "Setting domains to existing IntentFilterVerificationInfo for packageName: " + + packageName + " and with domains: " + ivi.getDomainsString()); } return ivi; } @@ -1021,7 +1028,7 @@ final class Settings { // Then, if we set a ALWAYS status, then put NEVER status for Apps whose IntentFilter // domains overlap the domains of the current package - ArraySet<String> currentDomains = current.getIntentFilterVerificationInfo().getDomainsSet(); + ArraySet<String> currentDomains = current.getIntentFilterVerificationInfo().getDomains(); if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { for (PackageSetting ps : mPackages.values()) { if (ps == null || ps.pkg.packageName.equals(packageName)) continue; @@ -1029,7 +1036,7 @@ final class Settings { if (ivi == null) { continue; } - ArraySet<String> set = ivi.getDomainsSet(); + ArraySet<String> set = ivi.getDomains(); set.retainAll(currentDomains); if (set.size() > 0) { ps.setDomainVerificationStatusForUser( @@ -3603,8 +3610,8 @@ final class Settings { return pkg.getCurrentEnabledStateLPr(classNameStr, userId); } - boolean setPackageStoppedStateLPw(String packageName, boolean stopped, - boolean allowedByPermission, int uid, int userId) { + boolean setPackageStoppedStateLPw(PackageManagerService yucky, String packageName, + boolean stopped, boolean allowedByPermission, int uid, int userId) { int appId = UserHandle.getAppId(uid); final PackageSetting pkgSetting = mPackages.get(packageName); if (pkgSetting == null) { @@ -3628,7 +3635,7 @@ final class Settings { // pkgSetting.pkg.mSetStopped = stopped; if (pkgSetting.getNotLaunched(userId)) { if (pkgSetting.installerPackageName != null) { - PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, + yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgSetting.name, null, pkgSetting.installerPackageName, null, new int[] {userId}); } @@ -3759,6 +3766,10 @@ final class Settings { pw.print(Integer.toHexString(System.identityHashCode(ps))); pw.println("):"); + if (ps.frozen) { + pw.print(prefix); pw.println(" FROZEN!"); + } + if (ps.realName != null) { pw.print(prefix); pw.print(" compat name="); pw.println(ps.name); @@ -3790,9 +3801,6 @@ final class Settings { pw.print(prefix); pw.print(" priavateFlags="); printFlags(pw, ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); - if (ps.pkg.mOperationPending) { - pw.print(prefix); pw.println(" mOperationPending=true"); - } pw.print(prefix); pw.print(" supportsScreens=["); boolean first = true; if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { @@ -4157,19 +4165,11 @@ final class Settings { } public void writePermissionsForUserSyncLPr(int userId) { - if (!PackageManagerService.RUNTIME_PERMISSIONS_ENABLED) { - return; - } - mHandler.removeMessages(userId); writePermissionsSync(userId); } public void writePermissionsForUserAsyncLPr(int userId) { - if (!PackageManagerService.RUNTIME_PERMISSIONS_ENABLED) { - return; - } - final long currentTimeMillis = SystemClock.uptimeMillis(); if (mWriteScheduled.get(userId)) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5536d4d..51503ec 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -285,6 +285,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for haptic feedback during boot when safe mode is enabled. long[] mSafeModeEnabledVibePattern; + // Vibrator pattern for haptic feedback of a stylus button press. + long[] mStylusButtonPressVibePattern; + /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ boolean mEnableShiftMenuBugReports = false; @@ -1436,6 +1439,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); + mStylusButtonPressVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_stylusButtonPressVibePattern); mScreenshotChordEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableScreenshotChord); @@ -2668,6 +2673,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } return -1; + } else if (keyCode == KeyEvent.KEYCODE_N && event.isMetaPressed()) { + if (down) { + IStatusBarService service = getStatusBarService(); + if (service != null) { + try { + service.expandNotificationsPanel(); + } catch (RemoteException e) { + // do nothing. + } + } + } } else if (keyCode == KeyEvent.KEYCODE_ASSIST) { if (down) { if (repeatCount == 0) { @@ -6164,6 +6180,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.SAFE_MODE_ENABLED: pattern = mSafeModeEnabledVibePattern; break; + case HapticFeedbackConstants.STYLUS_BUTTON_PRESS: + pattern = mStylusButtonPressVibePattern; + break; default: return false; } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 1e0185d..84eab42 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -390,7 +390,7 @@ public final class ShutdownThread extends Thread { } } - rebootOrShutdown(mReboot, mRebootReason); + rebootOrShutdown(mContext, mReboot, mRebootReason); } private void shutdownRadios(int timeout) { @@ -507,17 +507,18 @@ public final class ShutdownThread extends Thread { * Do not call this directly. Use {@link #reboot(Context, String, boolean)} * or {@link #shutdown(Context, boolean)} instead. * + * @param context Context used to vibrate or null without vibration * @param reboot true to reboot or false to shutdown * @param reason reason for reboot */ - public static void rebootOrShutdown(boolean reboot, String reason) { + public static void rebootOrShutdown(final Context context, boolean reboot, String reason) { if (reboot) { Log.i(TAG, "Rebooting, reason: " + reason); PowerManagerService.lowLevelReboot(reason); Log.e(TAG, "Reboot failed, will attempt shutdown instead"); - } else if (SHUTDOWN_VIBRATE_MS > 0) { + } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) { // vibrate before shutting down - Vibrator vibrator = new SystemVibrator(); + Vibrator vibrator = new SystemVibrator(context); try { vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES); } catch (Exception e) { diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 7d2fb43..726db4e 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -227,7 +227,7 @@ public class TrustManagerService extends SystemService { if (!userInfo.supportsSwitchTo()) continue; if (!mActivityManager.isUserRunning(userInfo.id)) continue; if (!lockPatternUtils.isSecure(userInfo.id)) continue; - if (!mUserHasAuthenticatedSinceBoot.get(userInfo.id)) continue; + if (!getUserHasAuthenticated(userInfo.id)) continue; DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager(); int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id); final boolean disableTrustAgents = @@ -506,7 +506,7 @@ public class TrustManagerService extends SystemService { // Agent dispatch and aggregation private boolean aggregateIsTrusted(int userId) { - if (!mUserHasAuthenticatedSinceBoot.get(userId)) { + if (!getUserHasAuthenticated(userId)) { return false; } for (int i = 0; i < mActiveAgents.size(); i++) { @@ -521,7 +521,7 @@ public class TrustManagerService extends SystemService { } private boolean aggregateIsTrustManaged(int userId) { - if (!mUserHasAuthenticatedSinceBoot.get(userId)) { + if (!getUserHasAuthenticated(userId)) { return false; } for (int i = 0; i < mActiveAgents.size(); i++) { @@ -549,23 +549,46 @@ public class TrustManagerService extends SystemService { } private void updateUserHasAuthenticated(int userId) { - if (!mUserHasAuthenticatedSinceBoot.get(userId)) { - mUserHasAuthenticatedSinceBoot.put(userId, true); + boolean changed = setUserHasAuthenticated(userId); + if (changed) { refreshAgentList(userId); } } + private boolean getUserHasAuthenticated(int userId) { + synchronized (mUserHasAuthenticatedSinceBoot) { + return mUserHasAuthenticatedSinceBoot.get(userId); + } + } - private void requireCredentialEntry(int userId) { - if (userId == UserHandle.USER_ALL) { - mUserHasAuthenticatedSinceBoot.clear(); - refreshAgentList(UserHandle.USER_ALL); - } else { - mUserHasAuthenticatedSinceBoot.put(userId, false); - refreshAgentList(userId); + /** + * @return whether the value has changed + */ + private boolean setUserHasAuthenticated(int userId) { + synchronized (mUserHasAuthenticatedSinceBoot) { + if (!mUserHasAuthenticatedSinceBoot.get(userId)) { + mUserHasAuthenticatedSinceBoot.put(userId, true); + return true; + } + return false; } } + private void clearUserHasAuthenticated(int userId) { + synchronized (mUserHasAuthenticatedSinceBoot) { + if (userId == UserHandle.USER_ALL) { + mUserHasAuthenticatedSinceBoot.clear(); + } else { + mUserHasAuthenticatedSinceBoot.put(userId, false); + } + } + } + + private void requireCredentialEntry(int userId) { + clearUserHasAuthenticated(userId); + refreshAgentList(userId); + } + // Listeners private void addListener(ITrustListener listener) { @@ -705,6 +728,18 @@ public class TrustManagerService extends SystemService { } } + @Override + public boolean hasUserAuthenticatedSinceBoot(int userId) throws RemoteException { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, null); + long token = Binder.clearCallingIdentity(); + try { + return getUserHasAuthenticated(userId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + private void enforceReportPermission() { mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events"); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d4b3dab..6bf68e8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -332,6 +332,7 @@ public class WindowManagerService extends IWindowManager.Stub final boolean mHasPermanentDpad; final long mDrawLockTimeoutMillis; + final boolean mAllowAnimationsInLowPowerMode; final boolean mAllowBootMessages; @@ -899,6 +900,8 @@ public class WindowManagerService extends IWindowManager.Stub com.android.internal.R.bool.config_defaultInTouchMode); mDrawLockTimeoutMillis = context.getResources().getInteger( com.android.internal.R.integer.config_drawLockTimeoutMillis); + mAllowAnimationsInLowPowerMode = context.getResources().getBoolean( + com.android.internal.R.bool.config_allowAnimationsInLowPowerMode); mInputManager = inputManager; // Must be before createDisplayContentLocked. mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mDisplaySettings = new DisplaySettings(); @@ -924,7 +927,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void onLowPowerModeChanged(boolean enabled) { synchronized (mWindowMap) { - if (mAnimationsDisabled != enabled) { + if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) { mAnimationsDisabled = enabled; dispatchNewAnimatorScaleLocked(null); } diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp index ad1d0f5..8f4fb51 100644 --- a/services/core/jni/com_android_server_AssetAtlasService.cpp +++ b/services/core/jni/com_android_server_AssetAtlasService.cpp @@ -64,7 +64,8 @@ namespace android { static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject, jobject graphicBuffer, jobject bitmapHandle) { - SkBitmap& bitmap = *GraphicsJNI::getSkBitmap(env, bitmapHandle); + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(env, bitmapHandle, &bitmap); SkAutoLockPixels alp(bitmap); // The goal of this method is to copy the bitmap into the GraphicBuffer diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index c50d63c..64514a9 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -25,7 +25,7 @@ namespace android { -static void android_server_SystemServer_nativeInit(JNIEnv* /* env */, jobject /* clazz */) { +static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) { char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsensorservice", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { @@ -39,7 +39,7 @@ static void android_server_SystemServer_nativeInit(JNIEnv* /* env */, jobject /* */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "nativeInit", "()V", (void*) android_server_SystemServer_nativeInit }, + { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService }, }; int register_android_server_SystemServer(JNIEnv* env) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f801d2d..6f01ca0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -161,7 +161,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_STATUS_BAR = "statusbar"; - private static final String ATTR_ENABLED = "enabled"; + private static final String ATTR_DISABLED = "disabled"; private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML = "do-not-ask-credentials-on-boot"; @@ -313,7 +313,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // This is the list of component allowed to start lock task mode. List<String> mLockTaskPackages = new ArrayList<>(); - boolean mStatusBarEnabledState = true; + boolean mStatusBarDisabled = false; ComponentName mRestrictionsProvider; @@ -1476,9 +1476,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, TAG_LOCK_TASK_COMPONENTS); } - if (!policy.mStatusBarEnabledState) { + if (policy.mStatusBarDisabled) { out.startTag(null, TAG_STATUS_BAR); - out.attribute(null, ATTR_ENABLED, Boolean.toString(policy.mStatusBarEnabledState)); + out.attribute(null, ATTR_DISABLED, Boolean.toString(policy.mStatusBarDisabled)); out.endTag(null, TAG_STATUS_BAR); } @@ -1615,8 +1615,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); } else if (TAG_STATUS_BAR.equals(tag)) { - policy.mStatusBarEnabledState = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_ENABLED)); + policy.mStatusBarDisabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_DISABLED)); } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { policy.doNotAskCredentialsOnBoot = true; } else { @@ -1678,8 +1678,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { updateMaximumTimeToLockLocked(policy); addDeviceInitializerToLockTaskPackagesLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); - if (!policy.mStatusBarEnabledState) { - setStatusBarEnabledStateInternal(policy.mStatusBarEnabledState, userHandle); + if (policy.mStatusBarDisabled) { + setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle); } updatePreferredSetupActivityLocked(userHandle); } @@ -4065,11 +4065,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); synchronized (this) { - if (mDeviceOwner != null) { - return mDeviceOwner.getDeviceOwnerName(); + if (mDeviceOwner == null || !mDeviceOwner.hasDeviceOwner()) { + return null; } + String deviceOwnerPackage = mDeviceOwner.getDeviceOwnerPackageName(); + return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_OWNER); } - return null; } // Returns the active device owner or null if there is no device owner. @@ -4274,7 +4275,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DevicePolicyData policy = getUserData(userId); policy.mPermissionPolicy = DevicePolicyManager.PERMISSION_POLICY_PROMPT; policy.mDelegatedCertInstallerPackage = null; - policy.mStatusBarEnabledState = true; + policy.mStatusBarDisabled = false; saveSettingsLocked(userId); long ident = Binder.clearCallingIdentity(); @@ -4426,7 +4427,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (profileOwner == null) { return null; } - DevicePolicyData policy = getUserData(userHandle); final int n = policy.mAdminList.size(); for (int i = 0; i < n; i++) { @@ -4444,13 +4444,37 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); + ComponentName profileOwner = getProfileOwner(userHandle); + if (profileOwner == null) { + return null; + } + return getApplicationLabel(profileOwner.getPackageName(), userHandle); + } - synchronized (this) { - if (mDeviceOwner != null) { - return mDeviceOwner.getProfileOwnerName(userHandle); + /** + * Canonical name for a given package. + */ + private String getApplicationLabel(String packageName, int userHandle) { + long token = Binder.clearCallingIdentity(); + try { + final Context userContext; + try { + UserHandle handle = new UserHandle(userHandle); + userContext = mContext.createPackageContextAsUser(packageName, 0, handle); + } catch (PackageManager.NameNotFoundException nnfe) { + Log.w(LOG_TAG, packageName + " is not installed for user " + userHandle, nnfe); + return null; } + ApplicationInfo appInfo = userContext.getApplicationInfo(); + CharSequence result = null; + if (appInfo != null) { + PackageManager pm = userContext.getPackageManager(); + result = pm.getApplicationLabel(appInfo); + } + return result != null ? result.toString() : null; + } finally { + Binder.restoreCallingIdentity(token); } - return null; } /** @@ -6002,7 +6026,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public boolean setKeyguardEnabledState(ComponentName who, boolean enabled) { + public boolean setKeyguardDisabled(ComponentName who, boolean disabled) { Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); @@ -6013,10 +6037,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long ident = Binder.clearCallingIdentity(); try { // disallow disabling the keyguard if a password is currently set - if (!enabled && utils.isSecure(userId)) { + if (disabled && utils.isSecure(userId)) { return false; } - utils.setLockScreenDisabled(!enabled, userId); + utils.setLockScreenDisabled(disabled, userId); } finally { Binder.restoreCallingIdentity(ident); } @@ -6024,35 +6048,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setStatusBarEnabledState(ComponentName who, boolean enabled) { + public boolean setStatusBarDisabled(ComponentName who, boolean disabled) { int userId = UserHandle.getCallingUserId(); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); DevicePolicyData policy = getUserData(userId); - if (policy.mStatusBarEnabledState != enabled) { - policy.mStatusBarEnabledState = enabled; - setStatusBarEnabledStateInternal(enabled, userId); + if (policy.mStatusBarDisabled != disabled) { + if (!setStatusBarDisabledInternal(disabled, userId)) { + return false; + } + policy.mStatusBarDisabled = disabled; saveSettingsLocked(userId); } } + return true; } - private void setStatusBarEnabledStateInternal(boolean enabled, int userId) { + private boolean setStatusBarDisabledInternal(boolean disabled, int userId) { long ident = Binder.clearCallingIdentity(); try { IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); if (statusBarService != null) { - int flags1 = enabled ? StatusBarManager.DISABLE_NONE : STATUS_BAR_DISABLE_MASK; - int flags2 = enabled ? StatusBarManager.DISABLE2_NONE : STATUS_BAR_DISABLE2_MASK; + int flags1 = disabled ? STATUS_BAR_DISABLE_MASK : StatusBarManager.DISABLE_NONE; + int flags2 = disabled ? STATUS_BAR_DISABLE2_MASK : StatusBarManager.DISABLE2_NONE; statusBarService.disableForUser(flags1, mToken, mContext.getPackageName(), userId); statusBarService.disable2ForUser(flags2, mToken, mContext.getPackageName(), userId); + return true; } } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to disable the status bar", e); } finally { Binder.restoreCallingIdentity(ident); } + return false; } /** @@ -6289,7 +6318,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void setPermissionPolicy(ComponentName admin, int policy) throws RemoteException { int userId = UserHandle.getCallingUserId(); synchronized (this) { - getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); DevicePolicyData userPolicy = getUserData(userId); if (userPolicy.mPermissionPolicy != policy) { userPolicy.mPermissionPolicy = policy; @@ -6312,7 +6341,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String permission, boolean granted) throws RemoteException { UserHandle user = Binder.getCallingUserHandle(); synchronized (this) { - getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long ident = Binder.clearCallingIdentity(); try { if (granted) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2922130..2d265e2 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -156,9 +156,9 @@ public final class SystemServer { private boolean mFirstBoot; /** - * Called to initialize native system services. + * Start the sensor service. */ - private static native void nativeInit(); + private static native void startSensorService(); /** * The main entry point from zygote. @@ -233,7 +233,6 @@ public final class SystemServer { // Initialize native services. System.loadLibrary("android_servers"); - nativeInit(); // Check whether we failed to shut down last time we tried. // This call may not return. @@ -285,7 +284,7 @@ public final class SystemServer { reason = null; } - ShutdownThread.rebootOrShutdown(reboot, reason); + ShutdownThread.rebootOrShutdown(null, reboot, reason); } } @@ -359,6 +358,10 @@ public final class SystemServer { // Set up the Application instance for the system process and get started. mActivityManagerService.setSystemProcess(); + + // The sensor service needs access to package manager service, app ops + // service, and permissions service, therefore we start it after them. + startSensorService(); } /** diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index c2e61c6..117cbe4 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -28,6 +28,7 @@ import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; +import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -56,6 +57,7 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemConfig; @@ -96,6 +98,7 @@ public class UsageStatsService extends SystemService implements Handler mHandler; AppOpsManager mAppOps; UserManager mUserManager; + AppWidgetManager mAppWidgetManager; private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>(); private File mUsageStatsDir; @@ -158,6 +161,7 @@ public class UsageStatsService extends SystemService implements if (phase == PHASE_SYSTEM_SERVICES_READY) { // Observe changes to the threshold new SettingsObserver(mHandler).registerObserver(); + mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class); } else if (phase == PHASE_BOOT_COMPLETED) { setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging()); } @@ -500,6 +504,11 @@ public class UsageStatsService extends SystemService implements return false; } + if (mAppWidgetManager != null + && mAppWidgetManager.isBoundWidgetPackage(packageName, userId)) { + return false; + } + final long lastUsed = getLastPackageAccessTime(packageName, userId); return hasPassedIdleDuration(lastUsed); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 81c5e6a..2897c61 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -28,7 +28,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.soundtrigger.IRecognitionStatusCallback; @@ -726,6 +725,24 @@ public class VoiceInteractionManagerService extends SystemService { } @Override + public void launchVoiceAssistFromKeyguard() { + enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction" + + "service"); + return; + } + final long caller = Binder.clearCallingIdentity(); + try { + mImpl.launchVoiceAssistFromKeyguard(); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + } + + @Override public boolean isSessionRunning() { enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); synchronized (this) { @@ -734,10 +751,18 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public boolean activeServiceSupportsAssistGesture() { + public boolean activeServiceSupportsAssist() { + enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); + synchronized (this) { + return mImpl != null && mImpl.mInfo.getSupportsAssist(); + } + } + + @Override + public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException { enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); synchronized (this) { - return mImpl != null && mImpl.mInfo.getSupportsAssistGesture(); + return mImpl != null && mImpl.mInfo.getSupportsLaunchFromKeyguard(); } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index f439915..0a5b668 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -235,6 +235,18 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } + public void launchVoiceAssistFromKeyguard() { + if (mService == null) { + Slog.w(TAG, "Not bound to voice interaction service " + mComponent); + return; + } + try { + mService.launchVoiceAssistFromKeyguard(); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException while calling launchVoiceAssistFromKeyguard", e); + } + } + void shutdownLocked() { try { if (mService != null) { @@ -256,6 +268,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne void notifySoundModelsChangedLocked() { if (mService == null) { Slog.w(TAG, "Not bound to voice interaction service " + mComponent); + return; } try { mService.soundModelsChanged(); |