diff options
Diffstat (limited to 'services')
30 files changed, 1259 insertions, 524 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index bb5ff1b..82a77d2 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3154,6 +3154,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: case WindowManager.LayoutParams.TYPE_PHONE: case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java index 66cc29a..26f4232 100644 --- a/services/core/java/com/android/server/AssetAtlasService.java +++ b/services/core/java/com/android/server/AssetAtlasService.java @@ -199,11 +199,6 @@ public class AssetAtlasService extends IAssetAtlas.Stub { private final ArrayList<Bitmap> mBitmaps; private final int mPixelCount; - private long mNativeBitmap; - - // Used for debugging only - private Bitmap mAtlasBitmap; - Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) { mBitmaps = bitmaps; mPixelCount = pixelCount; @@ -258,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(); @@ -268,108 +264,78 @@ 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(); - if (mNativeBitmap != 0) { - result = nUploadAtlas(buffer, mNativeBitmap); - } - - 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) { - if (DEBUG_ATLAS_TEXTURE) { - mAtlasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - return new Canvas(mAtlasBitmap); - } else { - Canvas canvas = new Canvas(); - mNativeBitmap = nAcquireAtlasCanvas(canvas, width, height); - return canvas; - } - } - - /** * 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) { - canvas.setBitmap(null); File systemDirectory = new File(Environment.getDataDirectory(), "system"); File dataFile = new File(systemDirectory, "atlas.png"); 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 } catch (IOException e) { // Ignore } - - mAtlasBitmap.recycle(); - mAtlasBitmap = null; - } else { - nReleaseAtlasCanvas(canvas, mNativeBitmap); } } } - private static native long nAcquireAtlasCanvas(Canvas canvas, int width, int height); - private static native void nReleaseAtlasCanvas(Canvas canvas, long bitmap); - private static native boolean nUploadAtlas(GraphicBuffer buffer, long bitmap); + private static native boolean nUploadAtlas(GraphicBuffer buffer, Bitmap bitmap); @Override public boolean isCompatible(int ppid) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 26362a4..484908d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -163,6 +163,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final String NETWORK_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // How long to wait before putting up a "This network doesn't have an Internet connection, + // connect anyway?" dialog after the user selects a network that doesn't validate. + private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000; + // How long to delay to removal of a pending intent based request. // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS private final int mReleasePendingIntentDelayMs; @@ -326,6 +330,19 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT = 27; + /** + * used to specify whether a network should be used even if unvalidated. + * arg1 = whether to accept the network if it's unvalidated (1 or 0) + * arg2 = whether to remember this choice in the future (1 or 0) + * obj = network + */ + private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28; + + /** + * used to ask the user to confirm a connection to an unvalidated network. + * obj = network + */ + private static final int EVENT_PROMPT_UNVALIDATED = 29; /** Handler used for internal events. */ final private InternalHandler mHandler; @@ -1870,6 +1887,7 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("ERROR: created network explicitly selected."); } nai.networkMisc.explicitlySelected = true; + nai.networkMisc.acceptUnvalidated = (boolean) msg.obj; break; } case NetworkMonitor.EVENT_NETWORK_TESTED: { @@ -1893,6 +1911,9 @@ public class ConnectivityService extends IConnectivityManager.Stub android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), 0, null); + + // TODO: trigger a NetworkCapabilities update so that the dialog can know + // that the network is now validated and close itself. } break; } @@ -2256,6 +2277,91 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { + enforceConnectivityInternalPermission(); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_UNVALIDATED, + accept ? 1 : 0, always ? 1: 0, network)); + } + + private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) { + if (DBG) log("handleSetAcceptUnvalidated network=" + network + + " accept=" + accept + " always=" + always); + + NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) { + // Nothing to do. + return; + } + + if (nai.everValidated) { + // The network validated while the dialog box was up. Don't make any changes. There's a + // TODO in the dialog code to make it go away if the network validates; once that's + // implemented, taking action here will be confusing. + return; + } + + if (!nai.networkMisc.explicitlySelected) { + Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network"); + } + + if (accept != nai.networkMisc.acceptUnvalidated) { + int oldScore = nai.getCurrentScore(); + nai.networkMisc.acceptUnvalidated = accept; + rematchAllNetworksAndRequests(nai, oldScore); + sendUpdatedScoreToFactories(nai); + } + + if (always) { + nai.asyncChannel.sendMessage( + NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, accept ? 1 : 0); + } + + // TODO: should we also disconnect from the network if accept is false? + } + + private void scheduleUnvalidatedPrompt(NetworkAgentInfo nai) { + mHandler.sendMessageDelayed( + mHandler.obtainMessage(EVENT_PROMPT_UNVALIDATED, nai.network), + PROMPT_UNVALIDATED_DELAY_MS); + } + + private void handlePromptUnvalidated(Network network) { + NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + + // Only prompt if the network is unvalidated and was explicitly selected by the user, and if + // we haven't already been told to switch to it regardless of whether it validated or not. + if (nai == null || nai.everValidated || + !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) { + return; + } + + // TODO: What should we do if we've already switched to this network because we had no + // better option? There are two obvious alternatives. + // + // 1. Decide that there's no point prompting because this is our only usable network. + // However, because we didn't prompt, if later on a validated network comes along, we'll + // either a) silently switch to it - bad if the user wanted to connect to stay on this + // unvalidated network - or b) prompt the user at that later time - bad because the user + // might not understand why they are now being prompted. + // + // 2. Always prompt the user, even if we have no other network to use. The user could then + // try to find an alternative network to join (remember, if we got here, then the user + // selected this network manually). This is bad because the prompt isn't really very + // useful. + // + // For now we do #1, but we can revisit that later. + if (isDefaultNetwork(nai)) { + return; + } + + Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK, network); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClassName("com.android.settings", + "com.android.settings.wifi.WifiNoInternetDialog"); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + } + private class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); @@ -2326,6 +2432,14 @@ public class ConnectivityService extends IConnectivityManager.Stub handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1); break; } + case EVENT_SET_ACCEPT_UNVALIDATED: { + handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0); + break; + } + case EVENT_PROMPT_UNVALIDATED: { + handlePromptUnvalidated((Network) msg.obj); + break; + } case EVENT_SYSTEM_READY: { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { nai.networkMonitor.systemReady = true; @@ -4125,6 +4239,7 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyIfacesChanged(); notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); + scheduleUnvalidatedPrompt(networkAgent); if (networkAgent.isVPN()) { // Temporarily disable the default proxy (not global). synchronized (mProxyLock) { diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index cac2f5c..4c937f7 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -16,6 +16,13 @@ package com.android.server; +import static com.android.internal.util.XmlUtils.readIntAttribute; +import static com.android.internal.util.XmlUtils.readStringAttribute; +import static com.android.internal.util.XmlUtils.writeIntAttribute; +import static com.android.internal.util.XmlUtils.writeStringAttribute; +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.START_TAG; + import android.Manifest; import android.app.ActivityManagerNative; import android.app.AppOpsManager; @@ -55,9 +62,13 @@ import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.AtomicFile; +import android.util.DebugUtils; import android.util.Log; import android.util.Slog; +import android.util.Xml; +import libcore.io.IoUtils; import libcore.util.EmptyArray; import libcore.util.HexEncoding; @@ -66,14 +77,21 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IMediaContainerService; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.NativeDaemonConnector.Command; import com.android.server.NativeDaemonConnector.SensitiveArg; import com.android.server.pm.PackageManagerService; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; @@ -214,6 +232,57 @@ class MountService extends IMountService.Stub public static final int FstrimCompleted = 700; } + private static final String TAG_VOLUMES = "volumes"; + private static final String TAG_VOLUME = "volume"; + private static final String ATTR_TYPE = "type"; + private static final String ATTR_FS_UUID = "fsUuid"; + private static final String ATTR_NICKNAME = "nickname"; + private static final String ATTR_USER_FLAGS = "userFlags"; + + private final AtomicFile mMetadataFile; + + private static class VolumeMetadata { + public final int type; + public final String fsUuid; + public String nickname; + public int userFlags; + + public VolumeMetadata(int type, String fsUuid) { + this.type = type; + this.fsUuid = Preconditions.checkNotNull(fsUuid); + } + + public static VolumeMetadata read(XmlPullParser in) throws IOException { + final int type = readIntAttribute(in, ATTR_TYPE); + final String fsUuid = readStringAttribute(in, ATTR_FS_UUID); + final VolumeMetadata meta = new VolumeMetadata(type, fsUuid); + meta.nickname = readStringAttribute(in, ATTR_NICKNAME); + meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS); + return meta; + } + + public static void write(XmlSerializer out, VolumeMetadata meta) throws IOException { + out.startTag(null, TAG_VOLUME); + writeIntAttribute(out, ATTR_TYPE, meta.type); + writeStringAttribute(out, ATTR_FS_UUID, meta.fsUuid); + writeStringAttribute(out, ATTR_NICKNAME, meta.nickname); + writeIntAttribute(out, ATTR_USER_FLAGS, meta.userFlags); + out.endTag(null, TAG_VOLUME); + } + + public void dump(IndentingPrintWriter pw) { + pw.println("VolumeMetadata:"); + pw.increaseIndent(); + pw.printPair("type", DebugUtils.valueToString(VolumeInfo.class, "TYPE_", type)); + pw.printPair("fsUuid", fsUuid); + pw.printPair("nickname", nickname); + pw.printPair("userFlags", + DebugUtils.flagsToString(VolumeInfo.class, "USER_FLAG_", userFlags)); + pw.decreaseIndent(); + pw.println(); + } + } + /** * <em>Never</em> hold the lock while performing downcalls into vold, since * unsolicited events can suddenly appear to update data structures. @@ -222,11 +291,18 @@ class MountService extends IMountService.Stub @GuardedBy("mLock") private int[] mStartedUsers = EmptyArray.INT; + + /** Map from disk ID to disk */ @GuardedBy("mLock") private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>(); + /** Map from volume ID to disk */ @GuardedBy("mLock") private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>(); + /** Map from UUID to metadata */ + @GuardedBy("mLock") + private ArrayMap<String, VolumeMetadata> mMetadata = new ArrayMap<>(); + private DiskInfo findDiskById(String id) { synchronized (mLock) { final DiskInfo disk = mDisks.get(id); @@ -260,6 +336,15 @@ class MountService extends IMountService.Stub throw new IllegalArgumentException("No volume found for path " + path); } + private VolumeMetadata findOrCreateMetadataLocked(VolumeInfo vol) { + VolumeMetadata meta = mMetadata.get(vol.fsUuid); + if (meta == null) { + meta = new VolumeMetadata(vol.type, vol.fsUuid); + mMetadata.put(meta.fsUuid, meta); + } + return meta; + } + private static int sNextMtpIndex = 1; private static int allocateMtpIndex(String volId) { @@ -740,19 +825,29 @@ class MountService extends IMountService.Stub } case VoldResponseCode.DISK_VOLUME_CREATED: { if (cooked.length != 3) break; - final DiskInfo disk = mDisks.get(cooked[1]); + final String diskId = cooked[1]; final String volId = cooked[2]; + final DiskInfo disk = mDisks.get(diskId); if (disk != null) { - disk.volumes = ArrayUtils.appendElement(String.class, disk.volumes, volId); + disk.volumeIds = ArrayUtils.appendElement(String.class, disk.volumeIds, volId); + } + final VolumeInfo vol = mVolumes.get(volId); + if (vol != null) { + vol.diskId = diskId; } break; } case VoldResponseCode.DISK_VOLUME_DESTROYED: { if (cooked.length != 3) break; - final DiskInfo disk = mDisks.get(cooked[1]); + final String diskId = cooked[1]; final String volId = cooked[2]; + final DiskInfo disk = mDisks.get(diskId); if (disk != null) { - disk.volumes = ArrayUtils.removeElement(String.class, disk.volumes, volId); + disk.volumeIds = ArrayUtils.removeElement(String.class, disk.volumeIds, volId); + } + final VolumeInfo vol = mVolumes.get(volId); + if (vol != null) { + vol.diskId = null; } break; } @@ -789,6 +884,7 @@ class MountService extends IMountService.Stub if (vol != null) { vol.fsType = cooked[2]; } + mCallbacks.notifyVolumeMetadataChanged(vol.clone()); break; } case VoldResponseCode.VOLUME_FS_UUID_CHANGED: { @@ -797,6 +893,8 @@ class MountService extends IMountService.Stub if (vol != null) { vol.fsUuid = cooked[2]; } + refreshMetadataLocked(); + mCallbacks.notifyVolumeMetadataChanged(vol.clone()); break; } case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: { @@ -805,6 +903,7 @@ class MountService extends IMountService.Stub if (vol != null) { vol.fsLabel = cooked[2]; } + mCallbacks.notifyVolumeMetadataChanged(vol.clone()); break; } case VoldResponseCode.VOLUME_PATH_CHANGED: { @@ -891,6 +990,25 @@ class MountService extends IMountService.Stub } } + /** + * Refresh latest metadata into any currently active {@link VolumeInfo}. + */ + private void refreshMetadataLocked() { + final int size = mVolumes.size(); + for (int i = 0; i < size; i++) { + final VolumeInfo vol = mVolumes.valueAt(i); + final VolumeMetadata meta = mMetadata.get(vol.fsUuid); + + if (meta != null) { + vol.nickname = meta.nickname; + vol.userFlags = meta.userFlags; + } else { + vol.nickname = null; + vol.userFlags = 0; + } + } + } + private void enforcePermission(String perm) { mContext.enforceCallingOrSelfPermission(perm, perm); } @@ -939,6 +1057,13 @@ class MountService extends IMountService.Stub mLastMaintenance = mLastMaintenanceFile.lastModified(); } + mMetadataFile = new AtomicFile( + new File(Environment.getSystemSecureDirectory(), "storage.xml")); + + synchronized (mLock) { + readMetadataLocked(); + } + /* * Create the connection to vold with a maximum queue of twice the * amount of containers we'd ever expect to have. This keeps an @@ -962,6 +1087,61 @@ class MountService extends IMountService.Stub mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); } + private void readMetadataLocked() { + mMetadata.clear(); + + FileInputStream fis = null; + try { + fis = mMetadataFile.openRead(); + final XmlPullParser in = Xml.newPullParser(); + in.setInput(fis, null); + + int type; + while ((type = in.next()) != END_DOCUMENT) { + if (type == START_TAG) { + final String tag = in.getName(); + if (TAG_VOLUME.equals(tag)) { + final VolumeMetadata meta = VolumeMetadata.read(in); + mMetadata.put(meta.fsUuid, meta); + } + } + } + } catch (FileNotFoundException e) { + // Missing metadata is okay, probably first boot + } catch (IOException e) { + Slog.wtf(TAG, "Failed reading metadata", e); + } catch (XmlPullParserException e) { + Slog.wtf(TAG, "Failed reading metadata", e); + } finally { + IoUtils.closeQuietly(fis); + } + } + + private void writeMetadataLocked() { + FileOutputStream fos = null; + try { + fos = mMetadataFile.startWrite(); + + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + out.startDocument(null, true); + out.startTag(null, TAG_VOLUMES); + final int size = mMetadata.size(); + for (int i = 0; i < size; i++) { + final VolumeMetadata meta = mMetadata.valueAt(i); + VolumeMetadata.write(out, meta); + } + out.endTag(null, TAG_VOLUMES); + out.endDocument(); + + mMetadataFile.finishWrite(fos); + } catch (IOException e) { + if (fos != null) { + mMetadataFile.failWrite(fos); + } + } + } + /** * Exposed API calls below here */ @@ -1116,6 +1296,36 @@ class MountService extends IMountService.Stub } @Override + public void setVolumeNickname(String volId, String nickname) { + enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + waitForReady(); + + synchronized (mLock) { + final VolumeInfo vol = findVolumeById(volId); + final VolumeMetadata meta = findOrCreateMetadataLocked(vol); + meta.nickname = nickname; + refreshMetadataLocked(); + writeMetadataLocked(); + mCallbacks.notifyVolumeMetadataChanged(vol.clone()); + } + } + + @Override + public void setVolumeUserFlags(String volId, int flags, int mask) { + enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + waitForReady(); + + synchronized (mLock) { + final VolumeInfo vol = findVolumeById(volId); + final VolumeMetadata meta = findOrCreateMetadataLocked(vol); + meta.userFlags = (meta.userFlags & ~mask) | (flags & mask); + refreshMetadataLocked(); + writeMetadataLocked(); + mCallbacks.notifyVolumeMetadataChanged(vol.clone()); + } + } + + @Override public int[] getStorageUsers(String path) { enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); waitForReady(); @@ -1899,7 +2109,12 @@ class MountService extends IMountService.Stub } @Override - public VolumeInfo[] getVolumes() { + public VolumeInfo[] getVolumes(int flags) { + if ((flags & StorageManager.FLAG_ALL_METADATA) != 0) { + // TODO: implement support for returning all metadata + throw new UnsupportedOperationException(); + } + synchronized (mLock) { final VolumeInfo[] res = new VolumeInfo[mVolumes.size()]; for (int i = 0; i < mVolumes.size(); i++) { @@ -2412,6 +2627,7 @@ class MountService extends IMountService.Stub private static class Callbacks extends Handler { private static final int MSG_STORAGE_STATE_CHANGED = 1; private static final int MSG_VOLUME_STATE_CHANGED = 2; + private static final int MSG_VOLUME_METADATA_CHANGED = 3; private final RemoteCallbackList<IMountServiceListener> mCallbacks = new RemoteCallbackList<>(); @@ -2455,6 +2671,10 @@ class MountService extends IMountService.Stub callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); break; } + case MSG_VOLUME_METADATA_CHANGED: { + callback.onVolumeMetadataChanged((VolumeInfo) args.arg1); + break; + } } } @@ -2473,6 +2693,12 @@ class MountService extends IMountService.Stub args.argi3 = newState; obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget(); } + + private void notifyVolumeMetadataChanged(VolumeInfo vol) { + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = vol; + obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget(); + } } @Override @@ -2529,6 +2755,15 @@ class MountService extends IMountService.Stub vol.dump(pw); } pw.decreaseIndent(); + + pw.println(); + pw.println("Metadata:"); + pw.increaseIndent(); + for (int i = 0; i < mMetadata.size(); i++) { + final VolumeMetadata meta = mMetadata.valueAt(i); + meta.dump(pw); + } + pw.decreaseIndent(); } pw.println(); diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 794e1b0..772a15c 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -46,7 +46,6 @@ import java.util.ArrayList; /** This class calls its monitor every minute. Killing this process if they don't return **/ public class Watchdog extends Thread { static final String TAG = "Watchdog"; - static final boolean localLOGV = false || false; // Set this to true to use debug default values. static final boolean DB = false; @@ -73,7 +72,7 @@ public class Watchdog extends Thread { static Watchdog sWatchdog; /* This handler will be used to post message back onto the main thread */ - final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>(); + final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>(); final HandlerChecker mMonitorChecker; ContentResolver mResolver; ActivityManagerService mActivity; @@ -191,6 +190,17 @@ public class Watchdog extends Thread { } } + /** Monitor for checking the availability of binder threads. The monitor will block until + * there is a binder thread available to process in coming IPCs to make sure other processes + * can still communicate with the service. + */ + private static final class BinderThreadMonitor implements Watchdog.Monitor { + @Override + public void monitor() { + Binder.blockUntilThreadAvailable(); + } + } + public interface Monitor { void monitor(); } @@ -228,6 +238,9 @@ public class Watchdog extends Thread { // And the display thread. mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(), "display thread", DEFAULT_TIMEOUT)); + + // Initialize monitor for Binder threads. + addMonitor(new BinderThreadMonitor()); } public void init(Context context, ActivityManagerService activity) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b606353..f25808b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -26,10 +26,14 @@ import static com.android.internal.util.XmlUtils.readLongAttribute; import static com.android.internal.util.XmlUtils.writeBooleanAttribute; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; -import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.*; +import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; -import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; @@ -3982,13 +3986,13 @@ public final class ActivityManagerService extends ActivityManagerNative if (rootR == null) { Slog.w(TAG, "Finishing task with all activities already finished"); } - // Do not allow task to finish in Lock Task mode. - if (tr == mStackSupervisor.mLockTaskModeTask) { - if (rootR == r) { - Slog.i(TAG, "Not finishing task in lock task mode"); - mStackSupervisor.showLockTaskToast(); - return false; - } + // Do not allow task to finish if last task in lockTask mode. Launchable apps can + // finish themselves. + if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE && rootR == r && + mStackSupervisor.isLastLockedTask(tr)) { + Slog.i(TAG, "Not finishing task in lock task mode"); + mStackSupervisor.showLockTaskToast(); + return false; } if (mController != null) { // Find the first activity that is not finishing. @@ -4142,20 +4146,18 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); try { ActivityRecord r = ActivityRecord.isInStackLocked(token); - - ActivityRecord rootR = r.task.getRootActivity(); - // Do not allow task to finish in Lock Task mode. - if (r.task == mStackSupervisor.mLockTaskModeTask) { - if (rootR == r) { - mStackSupervisor.showLockTaskToast(); - return false; - } + if (r == null) { + return false; } - boolean res = false; - if (r != null) { - res = r.task.stack.finishActivityAffinityLocked(r); + + // Do not allow the last non-launchable task to finish in Lock Task mode. + final TaskRecord task = r.task; + if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE && + mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) { + mStackSupervisor.showLockTaskToast(); + return false; } - return res; + return task.stack.finishActivityAffinityLocked(r); } finally { Binder.restoreCallingIdentity(origId); } @@ -8336,9 +8338,9 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); try { int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot); - if (taskId >= 0) { - if ((mStackSupervisor.mLockTaskModeTask != null) - && (mStackSupervisor.mLockTaskModeTask.taskId == taskId)) { + final TaskRecord task = mRecentTasks.taskForIdLocked(taskId); + if (task != null) { + if (mStackSupervisor.isLockedTask(task)) { mStackSupervisor.showLockTaskToast(); return false; } @@ -8520,47 +8522,45 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void updateLockTaskPackages(int userId, String[] packages) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { + final int callingUid = Binder.getCallingUid(); + if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { throw new SecurityException("updateLockTaskPackage called from non-system process"); } synchronized (this) { mLockTaskPackages.put(userId, packages); + mStackSupervisor.onLockTaskPackagesUpdatedLocked(); } } - private boolean isLockTaskAuthorizedLocked(String pkg) { - String[] packages = mLockTaskPackages.get(mCurrentUserId); - if (packages == null) { - return false; - } - for (int i = packages.length - 1; i >= 0; --i) { - if (pkg.equals(packages[i])) { - return true; - } - } - return false; - } void startLockTaskModeLocked(TaskRecord task) { - final String pkg = task.intent.getComponent().getPackageName(); + if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) { + return; + } + // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode // is initiated by system after the pinning request was shown and locked mode is initiated // by an authorized app directly - boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID; + final int callingUid = Binder.getCallingUid(); + boolean isSystemInitiated = callingUid == Process.SYSTEM_UID; long ident = Binder.clearCallingIdentity(); try { - if (!isSystemInitiated && !isLockTaskAuthorizedLocked(pkg)) { - StatusBarManagerInternal statusBarManager = - LocalServices.getService(StatusBarManagerInternal.class); - if (statusBarManager != null) { - statusBarManager.showScreenPinningRequest(); + final ActivityStack stack = mStackSupervisor.getFocusedStack(); + if (!isSystemInitiated) { + task.mLockTaskUid = callingUid; + if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) { + // startLockTask() called by app and task mode is lockTaskModeDefault. + StatusBarManagerInternal statusBarManager = + LocalServices.getService(StatusBarManagerInternal.class); + if (statusBarManager != null) { + statusBarManager.showScreenPinningRequest(); + } + return; } - return; - } - final ActivityStack stack = mStackSupervisor.getFocusedStack(); - if (!isSystemInitiated && (stack == null || task != stack.topTask())) { - throw new IllegalArgumentException("Invalid task, not in foreground"); + if (stack == null || task != stack.topTask()) { + throw new IllegalArgumentException("Invalid task, not in foreground"); + } } mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ? ActivityManager.LOCK_TASK_MODE_PINNED : @@ -8614,23 +8614,15 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void stopLockTaskMode() { - // Verify that the user matches the package of the intent for the TaskRecord - // we are locked to or systtem. This will ensure the same caller for startLockTaskMode - // and stopLockTaskMode. - final int callingUid = Binder.getCallingUid(); - if (callingUid != Process.SYSTEM_UID) { - try { - String pkg = - mStackSupervisor.mLockTaskModeTask.intent.getComponent().getPackageName(); - int uid = mContext.getPackageManager().getPackageUid(pkg, - Binder.getCallingUserHandle().getIdentifier()); - if (uid != callingUid) { - throw new SecurityException("Invalid uid, expected " + uid); - } - } catch (NameNotFoundException e) { - Log.d(TAG, "stopLockTaskMode " + e); - return; - } + final TaskRecord lockTask = mStackSupervisor.getLockedTaskLocked(); + if (lockTask == null) { + // Our work here is done. + return; + } + // Ensure the same caller for startLockTaskMode and stopLockTaskMode. + if (getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED && + Binder.getCallingUid() != lockTask.mLockTaskUid) { + throw new SecurityException("Invalid uid, expected " + lockTask.mLockTaskUid); } long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 2362d28..6210d60 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2875,7 +2875,7 @@ final class ActivityStack { } if (endTask) { - mStackSupervisor.endLockTaskModeIfTaskEnding(task); + mStackSupervisor.removeLockedTaskLocked(task); } } else if (r.state != ActivityState.PAUSING) { // If the activity is PAUSING, we will complete the finish once @@ -3674,8 +3674,7 @@ final class ActivityStack { } Slog.i(TAG, "moveTaskToBack: " + tr); - - mStackSupervisor.endLockTaskModeIfTaskEnding(tr); + mStackSupervisor.removeLockedTaskLocked(tr); // If we have a watcher, preflight the move before committing to it. First check // for *other* available tasks, but if none are available, then try again allowing the @@ -4240,7 +4239,7 @@ final class ActivityStack { */ void removeTask(TaskRecord task, String reason, boolean notMoving) { if (notMoving) { - mStackSupervisor.endLockTaskModeIfTaskEnding(task); + mStackSupervisor.removeLockedTaskLocked(task); mWindowManager.removeTask(task.taskId); } @@ -4345,4 +4344,10 @@ final class ActivityStack { mFullscreen = Configuration.EMPTY.equals(mOverrideConfig); return !mOverrideConfig.equals(oldConfig); } + + void onLockTaskPackagesUpdatedLocked() { + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { + mTaskHistory.get(taskNdx).setLockTaskAuth(); + } + } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c2f6bfd..6908483 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -17,10 +17,14 @@ package com.android.server.am; import static android.Manifest.permission.START_ANY_ACTIVITY; +import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; +import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; +import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG; @@ -28,6 +32,10 @@ import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; import static com.android.server.am.ActivityStack.ActivityState.*; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; +import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; import android.app.Activity; import android.app.ActivityManager; @@ -261,17 +269,17 @@ public final class ActivityStackSupervisor implements DisplayListener { // TODO: Add listener for removal of references. /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ - private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); + private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>(); /** Mapping from displayId to display current state */ - private final SparseArray<ActivityDisplay> mActivityDisplays = - new SparseArray<ActivityDisplay>(); + private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>(); InputManagerInternal mInputManagerInternal; - /** If non-null then the task specified remains in front and no other tasks may be started - * until the task exits or #stopLockTaskMode() is called. */ - TaskRecord mLockTaskModeTask; + /** The chain of tasks in lockTask mode. The current frontmost task is at the top, and tasks + * may be finished until there is only one entry left. If this is empty the system is not + * in lockTask mode. */ + ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>(); /** Store the current lock task mode. Possible values: * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, * {@link ActivityManager#LOCK_TASK_MODE_PINNED} @@ -282,8 +290,7 @@ public final class ActivityStackSupervisor implements DisplayListener { */ private LockTaskNotify mLockTaskNotify; - final ArrayList<PendingActivityLaunch> mPendingActivityLaunches - = new ArrayList<PendingActivityLaunch>(); + final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>(); /** Used to keep resumeTopActivityLocked() from being entered recursively */ boolean inResumeTopActivity; @@ -796,7 +803,7 @@ public final class ActivityStackSupervisor implements DisplayListener { ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); - ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); + ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<>(); runningTaskLists.add(stackTaskList); stack.getTasksLocked(stackTaskList, callingUid, allowed); } @@ -894,8 +901,8 @@ public final class ActivityStackSupervisor implements DisplayListener { intent = new Intent(intent); // Collect information about the target of the Intent. - ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, - profilerInfo, userId); + ActivityInfo aInfo = + resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId); ActivityContainer container = (ActivityContainer)iContainer; synchronized (mService) { @@ -1170,7 +1177,12 @@ public final class ActivityStackSupervisor implements DisplayListener { mService.updateLruProcessLocked(app, true, null); mService.updateOomAdjLocked(); - final ActivityStack stack = r.task.stack; + final TaskRecord task = r.task; + if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) { + setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "lockTaskLaunchMode attribute"); + } + + final ActivityStack stack = task.stack; try { if (app.thread == null) { throw new RemoteException(); @@ -1187,11 +1199,11 @@ public final class ActivityStackSupervisor implements DisplayListener { if (andResume) { EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId, System.identityHashCode(r), - r.task.taskId, r.shortComponentName); + task.taskId, r.shortComponentName); } if (r.isHomeActivity() && r.isNotResolverActivity()) { // Home process is the root process of the task. - mService.mHomeProcess = r.task.mActivities.get(0).app; + mService.mHomeProcess = task.mActivities.get(0).app; } mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); r.sleeping = false; @@ -1233,7 +1245,7 @@ public final class ActivityStackSupervisor implements DisplayListener { app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage, - r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, + task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo); if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { @@ -1946,7 +1958,7 @@ public final class ActivityStackSupervisor implements DisplayListener { if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r); } - if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { + if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and // the client said not to do anything if that // is the case, so this is it! And for paranoia, make @@ -1964,8 +1976,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } return ActivityManager.START_RETURN_INTENT_TO_CALLER; } - if ((launchFlags & - (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) + if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) { // The caller has requested to completely replace any // existing task with its new activity. Well that should @@ -2128,10 +2139,6 @@ public final class ActivityStackSupervisor implements DisplayListener { // Should this be considered a new task? if (r.resultTo == null && inTask == null && !addingToTask && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { - if (isLockTaskModeViolation(reuseTask)) { - Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); - return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; - } newTask = true; targetStack = computeStackFocus(r, newTask); targetStack.moveToFront("startingNewTask"); @@ -2147,6 +2154,10 @@ public final class ActivityStackSupervisor implements DisplayListener { } else { r.setTask(reuseTask, taskToAffiliate); } + if (isLockTaskModeViolation(r.task)) { + Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); + return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; + } if (!movedHome) { if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) @@ -3292,6 +3303,7 @@ public final class ActivityStackSupervisor implements DisplayListener { pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers); + pw.print(prefix); pw.println("mLockTaskModeTasks" + mLockTaskModeTasks); } ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { @@ -3592,6 +3604,32 @@ public final class ActivityStackSupervisor implements DisplayListener { return list; } + TaskRecord getLockedTaskLocked() { + final int top = mLockTaskModeTasks.size() - 1; + if (top >= 0) { + return mLockTaskModeTasks.get(top); + } + return null; + } + + boolean isLockedTask(TaskRecord task) { + return mLockTaskModeTasks.contains(task); + } + + boolean isLastLockedTask(TaskRecord task) { + return mLockTaskModeTasks.size() == 1 && mLockTaskModeTasks.contains(task); + } + + void removeLockedTaskLocked(final TaskRecord task) { + if (mLockTaskModeTasks.remove(task) && mLockTaskModeTasks.isEmpty()) { + // Last one. + final Message lockTaskMsg = Message.obtain(); + lockTaskMsg.arg1 = task.userId; + lockTaskMsg.what = LOCK_TASK_END_MSG; + mHandler.sendMessage(lockTaskMsg); + } + } + void showLockTaskToast() { mLockTaskNotify.showToast(mLockTaskModeState); } @@ -3599,42 +3637,93 @@ public final class ActivityStackSupervisor implements DisplayListener { void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) { if (task == null) { // Take out of lock task mode if necessary - if (mLockTaskModeTask != null) { - final Message lockTaskMsg = Message.obtain(); - lockTaskMsg.arg1 = mLockTaskModeTask.userId; - lockTaskMsg.what = LOCK_TASK_END_MSG; - mLockTaskModeTask = null; - mHandler.sendMessage(lockTaskMsg); + final TaskRecord lockedTask = getLockedTaskLocked(); + if (lockedTask != null) { + removeLockedTaskLocked(lockedTask); + if (!mLockTaskModeTasks.isEmpty()) { + // There are locked tasks remaining, can only finish this task, not unlock it. + lockedTask.performClearTaskLocked(); + resumeTopActivitiesLocked(); + return; + } } return; } + + // Should have already been checked, but do it again. + if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) { + return; + } if (isLockTaskModeViolation(task)) { - Slog.e(TAG, "setLockTaskMode: Attempt to start a second Lock Task Mode task."); + Slog.e(TAG, "setLockTaskMode: Attempt to start an unauthorized lock task."); return; } - mLockTaskModeTask = task; + + if (mLockTaskModeTasks.isEmpty()) { + // First locktask. + final Message lockTaskMsg = Message.obtain(); + lockTaskMsg.obj = task.intent.getComponent().getPackageName(); + lockTaskMsg.arg1 = task.userId; + lockTaskMsg.what = LOCK_TASK_START_MSG; + lockTaskMsg.arg2 = lockTaskModeState; + mHandler.sendMessage(lockTaskMsg); + } + // Add it or move it to the top. + mLockTaskModeTasks.remove(task); + mLockTaskModeTasks.add(task); + + if (task.mLockTaskUid == -1) { + task.mLockTaskUid = task.mCallingUid; + } findTaskToMoveToFrontLocked(task, 0, null, reason); resumeTopActivitiesLocked(); - - final Message lockTaskMsg = Message.obtain(); - lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName(); - lockTaskMsg.arg1 = mLockTaskModeTask.userId; - lockTaskMsg.what = LOCK_TASK_START_MSG; - lockTaskMsg.arg2 = lockTaskModeState; - mHandler.sendMessage(lockTaskMsg); } boolean isLockTaskModeViolation(TaskRecord task) { - return mLockTaskModeTask != null && mLockTaskModeTask != task; + if (getLockedTaskLocked() == task) { + return false; + } + final int lockTaskAuth = task.mLockTaskAuth; + switch (lockTaskAuth) { + case LOCK_TASK_AUTH_DONT_LOCK: + return !mLockTaskModeTasks.isEmpty(); + case LOCK_TASK_AUTH_LAUNCHABLE: + case LOCK_TASK_AUTH_WHITELISTED: + return false; + case LOCK_TASK_AUTH_PINNABLE: + // Pinnable tasks can't be launched on top of locktask tasks. + return !mLockTaskModeTasks.isEmpty(); + default: + Slog.w(TAG, "isLockTaskModeViolation: invalid lockTaskAuth value=" + lockTaskAuth); + return true; + } } - void endLockTaskModeIfTaskEnding(TaskRecord task) { - if (mLockTaskModeTask != null && mLockTaskModeTask == task) { - final Message lockTaskMsg = Message.obtain(); - lockTaskMsg.arg1 = mLockTaskModeTask.userId; - lockTaskMsg.what = LOCK_TASK_END_MSG; - mLockTaskModeTask = null; - mHandler.sendMessage(lockTaskMsg); + void onLockTaskPackagesUpdatedLocked() { + boolean didSomething = false; + for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx); + if (lockedTask.mLockTaskMode != LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED) { + continue; + } + final boolean wasLaunchable = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE; + lockedTask.setLockTaskAuth(); + if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) { + // Lost whitelisting authorization. End it now. + removeLockedTaskLocked(lockedTask); + lockedTask.performClearTaskLocked(); + didSomething = true; + } + } + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.onLockTaskPackagesUpdatedLocked(); + } + } + if (didSomething) { + resumeTopActivitiesLocked(); } } @@ -3734,11 +3823,10 @@ public final class ActivityStackSupervisor implements DisplayListener { mLockTaskModeState = msg.arg2; if (getStatusBarService() != null) { int flags = 0; - if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) { + if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) { flags = StatusBarManager.DISABLE_MASK & (~StatusBarManager.DISABLE_BACK); - } else if (mLockTaskModeState == - ActivityManager.LOCK_TASK_MODE_PINNED) { + } else if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) { flags = StatusBarManager.DISABLE_MASK & (~StatusBarManager.DISABLE_BACK) & (~StatusBarManager.DISABLE_HOME) @@ -3776,8 +3864,7 @@ public final class ActivityStackSupervisor implements DisplayListener { boolean shouldLockKeyguard = Settings.Secure.getInt( mService.mContext.getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0; - if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED && - shouldLockKeyguard) { + if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) { mWindowManager.lockNow(null); mWindowManager.dismissKeyguard(); new LockPatternUtils(mService.mContext) @@ -3789,7 +3876,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } catch (RemoteException ex) { throw new RuntimeException(ex); } finally { - mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE; + mLockTaskModeState = LOCK_TASK_MODE_NONE; } } break; case CONTAINER_CALLBACK_TASK_LIST_EMPTY: { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 82e6d47..790a78d 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -18,6 +18,10 @@ package com.android.server.am; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; @@ -121,6 +125,20 @@ final class TaskRecord { boolean mResizeable; // Activities in the task resizeable. Based on the resizable setting of // the root activity. + int mLockTaskMode; // Which tasklock mode to launch this task in. One of + // ActivityManager.LOCK_TASK_LAUNCH_MODE_* + /** Can't be put in lockTask mode. */ + final static int LOCK_TASK_AUTH_DONT_LOCK = 0; + /** Can enter lockTask with user approval if not already in lockTask. */ + final static int LOCK_TASK_AUTH_PINNABLE = 1; + /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */ + final static int LOCK_TASK_AUTH_LAUNCHABLE = 2; + /** Enters LOCK_TASK_MODE_LOCKED via startLockTask(), enters LOCK_TASK_MODE_PINNED from + * Overview. Can start over existing lockTask task. */ + final static int LOCK_TASK_AUTH_WHITELISTED = 3; + int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; + + int mLockTaskUid = -1; // The uid of the application that called startLockTask(). // This represents the last resolved activity values for this task // NOTE: This value needs to be persisted with each task @@ -186,6 +204,8 @@ final class TaskRecord { voiceInteractor = _voiceInteractor; isAvailable = true; mActivities = new ArrayList<>(); + mCallingUid = info.applicationInfo.uid; + mCallingPackage = info.packageName; setIntent(_intent, info); } @@ -201,12 +221,12 @@ final class TaskRecord { voiceInteractor = null; isAvailable = true; mActivities = new ArrayList<>(); + mCallingUid = info.applicationInfo.uid; + mCallingPackage = info.packageName; setIntent(_intent, info); taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; isPersistable = true; - mCallingUid = info.applicationInfo.uid; - mCallingPackage = info.packageName; // Clamp to [1, max]. maxRecents = Math.min(Math.max(info.maxRecents, 1), ActivityManager.getMaxAppRecentsLimitStatic()); @@ -215,8 +235,6 @@ final class TaskRecord { mTaskToReturnTo = HOME_ACTIVITY_TYPE; userId = UserHandle.getUserId(info.applicationInfo.uid); lastTaskDescription = _taskDescription; - mCallingUid = info.applicationInfo.uid; - mCallingPackage = info.packageName; } private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, @@ -278,9 +296,9 @@ final class TaskRecord { /** Sets the original intent, and the calling uid and package. */ void setIntent(ActivityRecord r) { - setIntent(r.intent, r.info); mCallingUid = r.launchedFromUid; mCallingPackage = r.launchedFromPackage; + setIntent(r.intent, r.info); } /** Sets the original intent, _without_ updating the calling uid or package. */ @@ -362,6 +380,8 @@ final class TaskRecord { autoRemoveRecents = false; } mResizeable = info.resizeable; + mLockTaskMode = info.lockTaskLaunchMode; + setLockTaskAuth(); } void setTaskToReturnTo(int taskToReturnTo) { @@ -716,6 +736,53 @@ final class TaskRecord { performClearTaskAtIndexLocked(0); } + private boolean isPrivileged() { + final ProcessRecord proc = mService.mProcessNames.get(mCallingPackage, mCallingUid); + if (proc != null) { + return (proc.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } + return false; + } + + void setLockTaskAuth() { + switch (mLockTaskMode) { + case LOCK_TASK_LAUNCH_MODE_DEFAULT: + mLockTaskAuth = isLockTaskWhitelistedLocked() ? + LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; + break; + + case LOCK_TASK_LAUNCH_MODE_NEVER: + mLockTaskAuth = isPrivileged() ? + LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE; + break; + + case LOCK_TASK_LAUNCH_MODE_ALWAYS: + mLockTaskAuth = isPrivileged() ? + LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE; + break; + + case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: + mLockTaskAuth = isLockTaskWhitelistedLocked() ? + LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; + break; + } + } + + boolean isLockTaskWhitelistedLocked() { + if (mCallingPackage == null) { + return false; + } + String[] packages = mService.mLockTaskPackages.get(userId); + if (packages == null) { + return false; + } + for (int i = packages.length - 1; i >= 0; --i) { + if (mCallingPackage.equals(packages[i])) { + return true; + } + } + return false; + } boolean isHomeTask() { return taskType == HOME_ACTIVITY_TYPE; } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 2d1f939..8a7c902 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -71,7 +71,10 @@ public class NetworkAgentInfo { private static final int UNVALIDATED_SCORE_PENALTY = 40; // Score for explicitly connected network. - private static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100; + // + // This ensures that a) the explicitly selected network is never trumped by anything else, and + // b) the explicitly selected network is never torn down. + private static final int MAXIMUM_NETWORK_SCORE = 100; // The list of NetworkRequests being satisfied by this Network. public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>(); @@ -123,13 +126,18 @@ public class NetworkAgentInfo { // score. The NetworkScore class would provide a nice place to centralize score constants // so they are not scattered about the transports. - int score = currentScore; + // If this network is explicitly selected and the user has decided to use it even if it's + // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly + // selected and we're trying to see what its score could be. This ensures that we don't tear + // down an explicitly selected network before the user gets a chance to prefer it when + // a higher-scoring network (e.g., Ethernet) is available. + if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { + return MAXIMUM_NETWORK_SCORE; + } + int score = currentScore; if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY; if (score < 0) score = 0; - - if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE; - return score; } @@ -156,7 +164,9 @@ public class NetworkAgentInfo { networkCapabilities + "} Score{" + getCurrentScore() + "} " + "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " + "created{" + created + "} " + - "explicitlySelected{" + networkMisc.explicitlySelected + "} }"; + "explicitlySelected{" + networkMisc.explicitlySelected + "} " + + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " + + "}"; } public String name() { diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 4173b78..7cccef2 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -1190,7 +1190,7 @@ public class SyncManager { while (operationIterator.hasNext()) { final SyncOperation op = operationIterator.next(); if (op.appIdle - && getPackageName(op.target).equals(packageName) + && (packageName == null || getPackageName(op.target).equals(packageName)) && (userId == UserHandle.USER_ALL || op.target.userId == userId)) { op.appIdle = false; clearBackoffSetting(op); diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index c150b60..0ca0c0e 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -39,6 +39,7 @@ import static android.Manifest.permission.USE_FINGERPRINT; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -51,9 +52,9 @@ import java.util.List; public class FingerprintService extends SystemService { private static final String TAG = "FingerprintService"; private static final boolean DEBUG = true; - private ClientData mAuthClient = null; - private ClientData mEnrollClient = null; - private ClientData mRemoveClient = null; + private ClientMonitor mAuthClient = null; + private ClientMonitor mEnrollClient = null; + private ClientMonitor mRemoveClient = null; private static final int MSG_NOTIFY = 10; @@ -63,7 +64,6 @@ public class FingerprintService extends SystemService { // Must agree with the list in fingerprint.h private static final int FINGERPRINT_ERROR = -1; private static final int FINGERPRINT_ACQUIRED = 1; - private static final int FINGERPRINT_PROCESSED = 2; private static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; private static final int FINGERPRINT_TEMPLATE_REMOVED = 4; private static final int FINGERPRINT_AUTHENTICATED = 5; @@ -83,80 +83,21 @@ public class FingerprintService extends SystemService { }; private Context mContext; private int mHalDeviceId; + private int mFailedAttempts; + private final Runnable mLockoutReset = new Runnable() { + @Override + public void run() { + resetFailedAttempts(); + } + }; private static final int STATE_IDLE = 0; private static final int STATE_AUTHENTICATING = 1; private static final int STATE_ENROLLING = 2; private static final int STATE_REMOVING = 3; private static final long MS_PER_SEC = 1000; - - private class ClientData { - IBinder token; - IFingerprintServiceReceiver receiver; - int userId; - long opId; - private TokenWatcher tokenWatcher; - public ClientData(IBinder token, long opId, IFingerprintServiceReceiver receiver, - int userId) { - this.token = token; - this.opId = opId; - this.receiver = receiver; - this.userId = userId; - tokenWatcher = new TokenWatcher(token); - try { - token.linkToDeath(tokenWatcher, 0); - } catch (RemoteException e) { - Slog.w(TAG, "caught remote exception in linkToDeath: ", e); - } - } - - IBinder getToken() { - return tokenWatcher.getToken(); - } - - public void destroy() { - token.unlinkToDeath(tokenWatcher, 0); - tokenWatcher.token = null; - } - } - - private class TokenWatcher implements IBinder.DeathRecipient { - WeakReference<IBinder> token; - - TokenWatcher(IBinder token) { - this.token = new WeakReference<IBinder>(token); - } - - IBinder getToken() { - return token.get(); - } - - public void binderDied() { - if (mAuthClient != null & mAuthClient.token == token) - mAuthClient = null; - if (mEnrollClient != null && mEnrollClient.token == token) - mEnrollClient = null; - this.token = null; - } - - protected void finalize() throws Throwable { - try { - if (token != null) { - if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token); - if (mAuthClient != null && mAuthClient.token == token) { - mAuthClient.destroy(); - mAuthClient = null; - } - if (mEnrollClient != null && mEnrollClient.token == token) { - mAuthClient.destroy(); - mEnrollClient = null; - } - } - } finally { - super.finalize(); - } - } - } + private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000; + private static final int MAX_FAILED_ATTEMPTS = 5; public FingerprintService(Context context) { super(context); @@ -166,11 +107,11 @@ public class FingerprintService extends SystemService { // TODO: Move these into separate process // JNI methods to communicate from FingerprintService to HAL - static native int nativeEnroll(long challenge, int groupId, int timeout); + static native int nativeEnroll(byte [] token, int groupId, int timeout); static native long nativePreEnroll(); static native int nativeStopEnrollment(); static native int nativeAuthenticate(long sessionId, int groupId); - static native int nativeStopAuthentication(long sessionId); + static native int nativeStopAuthentication(); static native int nativeRemove(int fingerId, int groupId); static native int nativeOpenHal(); static native int nativeCloseHal(); @@ -201,82 +142,62 @@ public class FingerprintService extends SystemService { Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" + ", mAuthClients = " + mAuthClient + ", mEnrollClient = " + mEnrollClient); if (mEnrollClient != null) { - try { - final IBinder token = mEnrollClient.token; - if (doNotify(mEnrollClient, type, arg1, arg2, arg3)) { - stopEnrollment(token); - } - } catch (RemoteException e) { - Slog.e(TAG, "can't send message to mEnrollClient. Did it die?", e); - mEnrollClient.destroy(); - mEnrollClient = null; + final IBinder token = mEnrollClient.token; + if (doNotify(mEnrollClient, type, arg1, arg2, arg3)) { + stopEnrollment(token); } } if (mAuthClient != null) { - try { - final IBinder token = mAuthClient.getToken(); - if (doNotify(mAuthClient, type, arg1, arg2, arg3)) { - stopAuthentication(token); - } - } catch (RemoteException e) { - Slog.e(TAG, "can't send message to mAuthClient. Did it die?", e); - mAuthClient.destroy(); - mAuthClient = null; + final IBinder token = mAuthClient.token; + if (doNotify(mAuthClient, type, arg1, arg2, arg3)) { + stopAuthentication(token); } } if (mRemoveClient != null) { - try { - if (doNotify(mRemoveClient, type, arg1, arg2, arg3)) { - mRemoveClient.destroy(); - mRemoveClient = null; - } - } catch (RemoteException e) { - Slog.e(TAG, "can't send message to mRemoveClient. Did it die?", e); - mRemoveClient.destroy(); - mRemoveClient = null; + if (doNotify(mRemoveClient, type, arg1, arg2, arg3)) { + removeClient(mRemoveClient); } } } // Returns true if the operation is done, i.e. authentication completed - boolean doNotify(ClientData clientData, int type, int arg1, int arg2, int arg3) - throws RemoteException { - if (clientData.receiver == null) { - if (DEBUG) Slog.v(TAG, "receiver not registered!!"); - return false; - } + boolean doNotify(ClientMonitor clientMonitor, int type, int arg1, int arg2, int arg3) { ContentResolver contentResolver = mContext.getContentResolver(); boolean operationCompleted = false; switch (type) { case FINGERPRINT_ERROR: - clientData.receiver.onError(mHalDeviceId, arg1 /* error */); - if (arg1 == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { - if (mEnrollClient != null) { - mEnrollClient.destroy(); - mEnrollClient = null; - } - if (mAuthClient != null) { - mAuthClient.destroy(); - mAuthClient = null; - } + { + final int error = arg1; + clientMonitor.sendError(error); + removeClient(clientMonitor); + operationCompleted = true; // any error means the operation is done } - operationCompleted = true; // any error means the operation is done break; case FINGERPRINT_ACQUIRED: - clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */); + clientMonitor.sendAcquired(arg1 /* acquireInfo */); break; - case FINGERPRINT_PROCESSED: - clientData.receiver.onProcessed(mHalDeviceId, arg1 /* fpId */, arg2 /* gpId */); - operationCompleted = true; // we either got a positive or negative match + case FINGERPRINT_AUTHENTICATED: + { + final int fpId = arg1; + final int groupId = arg2; + clientMonitor.sendAuthenticated(fpId, groupId); + if (fpId == 0) { + if (clientMonitor == mAuthClient) { + operationCompleted = handleFailedAttempt(clientMonitor); + } + } else { + mLockoutReset.run(); // a valid fingerprint resets lockout + } + } break; case FINGERPRINT_TEMPLATE_ENROLLING: { final int fpId = arg1; final int groupId = arg2; final int remaining = arg3; - clientData.receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining); + clientMonitor.sendEnrollResult(fpId, groupId, remaining); if (remaining == 0) { - addTemplateForUser(clientData, contentResolver, fpId); + addTemplateForUser(clientMonitor, contentResolver, fpId); operationCompleted = true; // enroll completed } } @@ -285,11 +206,11 @@ public class FingerprintService extends SystemService { { final int fingerId = arg1; final int groupId = arg2; - removeTemplateForUser(clientData, contentResolver, fingerId); + removeTemplateForUser(clientMonitor, contentResolver, fingerId); if (fingerId == 0) { operationCompleted = true; // remove completed } else { - clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId); + clientMonitor.sendRemoved(fingerId, groupId); } } break; @@ -297,24 +218,60 @@ public class FingerprintService extends SystemService { return operationCompleted; } - private void removeTemplateForUser(ClientData clientData, ContentResolver contentResolver, + private void removeClient(ClientMonitor clientMonitor) { + if (clientMonitor == null) return; + clientMonitor.destroy(); + if (clientMonitor == mAuthClient) { + mAuthClient = null; + } else if (clientMonitor == mEnrollClient) { + mEnrollClient = null; + } else if (clientMonitor == mRemoveClient) { + mRemoveClient = null; + } + } + + private boolean inLockoutMode() { + return mFailedAttempts > MAX_FAILED_ATTEMPTS; + } + + private void resetFailedAttempts() { + if (DEBUG) Slog.v(TAG, "Reset fingerprint lockout"); + mFailedAttempts = 0; + } + + private boolean handleFailedAttempt(ClientMonitor clientMonitor) { + mFailedAttempts++; + if (mFailedAttempts > MAX_FAILED_ATTEMPTS) { + // Failing multiple times will continue to push out the lockout time. + mHandler.removeCallbacks(mLockoutReset); + mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS); + if (clientMonitor != null + && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { + Slog.w(TAG, "Cannot send lockout message to client"); + } + return true; + } + return false; + } + + private void removeTemplateForUser(ClientMonitor clientMonitor, ContentResolver contentResolver, final int fingerId) { FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver, - clientData.userId); + clientMonitor.userId); } - private void addTemplateForUser(ClientData clientData, ContentResolver contentResolver, + private void addTemplateForUser(ClientMonitor clientMonitor, ContentResolver contentResolver, final int fingerId) { FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId, - clientData.userId); + clientMonitor.userId); } - void startEnrollment(IBinder token, long opId, - int groupId, IFingerprintServiceReceiver receiver, int flags) { + void startEnrollment(IBinder token, byte[] cryptoToken, int groupId, + IFingerprintServiceReceiver receiver, int flags) { stopPendingOperations(); - mEnrollClient = new ClientData(token, opId, receiver, groupId); + mEnrollClient = new ClientMonitor(token, receiver, groupId); final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); - final int result = nativeEnroll(opId, groupId, timeout); + final int result = nativeEnroll(cryptoToken, groupId, timeout); if (result != 0) { Slog.w(TAG, "startEnroll failed, result=" + result); } @@ -335,8 +292,11 @@ public class FingerprintService extends SystemService { } void stopEnrollment(IBinder token) { - if (mEnrollClient == null || mEnrollClient.token != token) return; + final ClientMonitor client = mEnrollClient; + if (client == null || client.token != token) return; int result = nativeStopEnrollment(); + client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); + removeClient(mEnrollClient); if (result != 0) { Slog.w(TAG, "startEnrollCancel failed, result=" + result); } @@ -345,7 +305,15 @@ public class FingerprintService extends SystemService { void startAuthentication(IBinder token, long opId, int groupId, IFingerprintServiceReceiver receiver, int flags) { stopPendingOperations(); - mAuthClient = new ClientData(token, opId, receiver, groupId); + mAuthClient = new ClientMonitor(token, receiver, groupId); + if (inLockoutMode()) { + Slog.v(TAG, "In lockout mode; disallowing authentication"); + if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { + Slog.w(TAG, "Cannot send timeout message to client"); + } + mAuthClient = null; + return; + } final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); final int result = nativeAuthenticate(opId, groupId); if (result != 0) { @@ -354,8 +322,11 @@ public class FingerprintService extends SystemService { } void stopAuthentication(IBinder token) { - if (mAuthClient == null || mAuthClient.token != token) return; - int result = nativeStopAuthentication(mAuthClient.opId); + final ClientMonitor client = mAuthClient; + if (client == null || client.token != token) return; + int result = nativeStopAuthentication(); + client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); + removeClient(mAuthClient); if (result != 0) { Slog.w(TAG, "stopAuthentication failed, result=" + result); } @@ -363,7 +334,7 @@ public class FingerprintService extends SystemService { void startRemove(IBinder token, int fingerId, int userId, IFingerprintServiceReceiver receiver) { - mRemoveClient = new ClientData(token, 0, receiver, userId); + mRemoveClient = new ClientMonitor(token, receiver, userId); // The fingerprint template ids will be removed when we get confirmation from the HAL final int result = nativeRemove(fingerId, userId); if (result != 0) { @@ -387,22 +358,124 @@ public class FingerprintService extends SystemService { return result; } + public boolean hasEnrolledFingerprints(int groupId) { + ContentResolver resolver = mContext.getContentResolver(); + return FingerprintUtils.getFingerprintIdsForUser(resolver, groupId).length > 0; + } + void checkPermission(String permission) { getContext().enforceCallingOrSelfPermission(permission, "Must have " + permission + " permission."); } - private static final class Message { + private class ClientMonitor implements IBinder.DeathRecipient { IBinder token; - long opId; - int groupId; - int flags; + WeakReference<IFingerprintServiceReceiver> receiver; + int userId; - public Message(IBinder token, long challenge, int groupId, int flags) { + public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId) { this.token = token; - this.opId = challenge; - this.groupId = groupId; - this.flags = flags; + this.receiver = new WeakReference<IFingerprintServiceReceiver>(receiver); + this.userId = userId; + try { + token.linkToDeath(this, 0); + } catch (RemoteException e) { + Slog.w(TAG, "caught remote exception in linkToDeath: ", e); + } + } + + public void destroy() { + if (token != null) { + token.unlinkToDeath(this, 0); + token = null; + } + receiver = null; + } + + public void binderDied() { + token = null; + removeClient(this); + } + + protected void finalize() throws Throwable { + try { + if (token != null) { + if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token); + removeClient(this); + } + } finally { + super.finalize(); + } + } + + private boolean sendRemoved(int fingerId, int groupId) { + IFingerprintServiceReceiver rx = receiver.get(); + if (rx != null) { + try { + rx.onRemoved(mHalDeviceId, fingerId, groupId); + return true; + } catch (RemoteException e) { + if (DEBUG) Slog.v(TAG, "Failed to invoke sendRemoved:", e); + } + } + removeClient(this); + return false; + } + + private boolean sendEnrollResult(int fpId, int groupId, int remaining) { + IFingerprintServiceReceiver rx = receiver.get(); + if (rx != null) { + try { + rx.onEnrollResult(mHalDeviceId, fpId, groupId, remaining); + return true; + } catch (RemoteException e) { + if (DEBUG) Slog.v(TAG, "Failed to invoke sendEnrollResult:", e); + } + } + removeClient(this); + return false; + } + + private boolean sendAuthenticated(int fpId, int groupId) { + IFingerprintServiceReceiver rx = receiver.get(); + if (rx != null) { + try { + rx.onAuthenticated(mHalDeviceId, fpId, groupId); + return true; + } catch (RemoteException e) { + if (DEBUG) Slog.v(TAG, "Failed to invoke sendProcessed:", e); + } + } + removeClient(this); + return false; + } + + private boolean sendAcquired(int acquiredInfo) { + IFingerprintServiceReceiver rx = receiver.get(); + if (rx != null) { + try { + rx.onAcquired(mHalDeviceId, acquiredInfo); + return true; + } catch (RemoteException e) { + if (DEBUG) Slog.v(TAG, "Failed to invoke sendAcquired:", e); + } + } + removeClient(this); + return false; + } + + private boolean sendError(int error) { + IFingerprintServiceReceiver rx = receiver.get(); + if (rx != null) { + try { + rx.onError(mHalDeviceId, error); + return true; + } catch (RemoteException e) { + if (DEBUG) Slog.v(TAG, "Failed to invoke sendError:", e); + } + } + removeClient(this); + return false; } } @@ -415,13 +488,14 @@ public class FingerprintService extends SystemService { @Override // Binder call - public void enroll(final IBinder token, final long opid, final int groupId, + public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId, final IFingerprintServiceReceiver receiver, final int flags) { checkPermission(MANAGE_FINGERPRINT); + final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length); mHandler.post(new Runnable() { @Override public void run() { - startEnrollment(token, opid, groupId, receiver, flags); + startEnrollment(token, cryptoClone, groupId, receiver, flags); } }); } @@ -503,6 +577,13 @@ public class FingerprintService extends SystemService { checkPermission(USE_FINGERPRINT); return FingerprintService.this.getEnrolledFingerprints(groupId); } + + @Override + // Binder call + public boolean hasEnrolledFingerprints(int groupId) { + checkPermission(USE_FINGERPRINT); + return FingerprintService.this.hasEnrolledFingerprints(groupId); + } } @Override diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java index 834dff2..1fb22be 100644 --- a/services/core/java/com/android/server/location/FlpHardwareProvider.java +++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java @@ -42,11 +42,13 @@ import android.util.Log; * {@hide} */ public class FlpHardwareProvider { + private static final int FIRST_VERSION_WITH_FLUSH_LOCATIONS = 2; private GeofenceHardwareImpl mGeofenceHardwareSink = null; private IFusedLocationHardwareSink mLocationSink = null; // Capabilities provided by FlpCallbacks private boolean mHaveBatchingCapabilities; private int mBatchingCapabilities; + private int mVersion; private static FlpHardwareProvider sSingletonInstance = null; @@ -150,6 +152,11 @@ public class FlpHardwareProvider { } } + private void setVersion(int version) { + mVersion = version; + getGeofenceHardwareSink().setVersion(version); + } + private void maybeSendCapabilities() { IFusedLocationHardwareSink sink; boolean haveBatchingCapabilities; @@ -366,7 +373,12 @@ public class FlpHardwareProvider { @Override public void flushBatchedLocations() { - nativeFlushBatchedLocations(); + if (mVersion >= FIRST_VERSION_WITH_FLUSH_LOCATIONS) { + nativeFlushBatchedLocations(); + } else { + Log.wtf(TAG, + "Tried to call flushBatchedLocations on an unsupported implementation"); + } } @Override @@ -388,6 +400,11 @@ public class FlpHardwareProvider { public void injectDeviceContext(int deviceEnabledContext) { nativeInjectDeviceContext(deviceEnabledContext); } + + @Override + public int getVersion() { + return mVersion; + } }; private final IFusedGeofenceHardware mGeofenceHardwareService = diff --git a/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java index e49c411..a08d326 100644 --- a/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java +++ b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java @@ -122,4 +122,10 @@ public class FusedLocationHardwareSecure extends IFusedLocationHardware.Stub { checkPermissions(); mLocationHardware.flushBatchedLocations(); } + + @Override + public int getVersion() throws RemoteException { + checkPermissions(); + return mLocationHardware.getVersion(); + } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 4cf2909..997d546 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -29,9 +29,11 @@ import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.INotificationManager; +import android.app.INotificationManagerCallback; import android.app.ITransientNotification; import android.app.Notification; import android.app.NotificationManager; +import android.app.NotificationManager.Policy; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; @@ -227,6 +229,8 @@ public class NotificationManagerService extends SystemService { new ArrayMap<String, NotificationRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); + private final ArrayMap<String, Policy.Token> mPolicyTokens = new ArrayMap<>(); + // The last key in this list owns the hardware. ArrayList<String> mLights = new ArrayList<>(); @@ -893,6 +897,13 @@ public class NotificationManagerService extends SystemService { updateInterruptionFilterLocked(); } } + + @Override + void onPolicyChanged() { + getContext().sendBroadcast( + new Intent(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); + } }); final File systemDir = new File(Environment.getDataDirectory(), "system"); mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); @@ -1551,6 +1562,18 @@ public class NotificationManagerService extends SystemService { message); } + private void enforcePolicyToken(Policy.Token token, String method) { + if (!checkPolicyToken(token)) { + Slog.w(TAG, "Invalid notification policy token calling " + method); + throw new SecurityException("Invalid notification policy token"); + } + } + + private boolean checkPolicyToken(Policy.Token token) { + return mPolicyTokens.containsValue(token) + || mListeners.mPolicyTokens.containsValue(token); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -1586,24 +1609,73 @@ public class NotificationManagerService extends SystemService { enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled"); return mConditionProviders.isSystemProviderEnabled(path); } - }; - private String[] getActiveNotificationKeys(INotificationListener token) { - final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - final ArrayList<String> keys = new ArrayList<String>(); - if (info.isEnabledForCurrentProfiles()) { - synchronized (mNotificationList) { - final int N = mNotificationList.size(); - for (int i = 0; i < N; i++) { - final StatusBarNotification sbn = mNotificationList.get(i).sbn; - if (info.enabledAndUserMatches(sbn.getUserId())) { - keys.add(sbn.getKey()); + @Override + public Policy.Token getPolicyTokenFromListener(INotificationListener listener) { + final long identity = Binder.clearCallingIdentity(); + try { + return mListeners.getPolicyToken(listener); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void requestNotificationPolicyToken(String pkg, + INotificationManagerCallback callback) throws RemoteException { + if (callback == null) { + Slog.w(TAG, "requestNotificationPolicyToken: no callback specified"); + return; + } + if (pkg == null) { + Slog.w(TAG, "requestNotificationPolicyToken denied: no package specified"); + callback.onPolicyToken(null); + return; + } + Policy.Token token = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mNotificationList) { + token = mPolicyTokens.get(pkg); + if (token == null) { + token = new Policy.Token(new Binder()); + mPolicyTokens.put(pkg, token); } + if (DBG) Slog.w(TAG, "requestNotificationPolicyToken granted for " + pkg); } + } finally { + Binder.restoreCallingIdentity(identity); } + callback.onPolicyToken(token); + } + + @Override + public boolean isNotificationPolicyTokenValid(String pkg, Policy.Token token) { + return checkPolicyToken(token); } - return keys.toArray(new String[keys.size()]); - } + + @Override + public Policy getNotificationPolicy(Policy.Token token) { + enforcePolicyToken(token, "getNotificationPolicy"); + final long identity = Binder.clearCallingIdentity(); + try { + return mZenModeHelper.getNotificationPolicy(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void setNotificationPolicy(Policy.Token token, Policy policy) { + enforcePolicyToken(token, "setNotificationPolicy"); + final long identity = Binder.clearCallingIdentity(); + try { + mZenModeHelper.setNotificationPolicy(policy); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + }; private String disableNotificationEffects(NotificationRecord record) { if (mDisableNotificationEffects) { @@ -1718,6 +1790,10 @@ public class NotificationManagerService extends SystemService { pw.print(listener.component); } pw.println(')'); + pw.print(" mPolicyTokens.keys: "); + pw.println(TextUtils.join(",", mPolicyTokens.keySet())); + pw.print(" mListeners.mPolicyTokens.keys: "); + pw.println(TextUtils.join(",", mListeners.mPolicyTokens.keySet())); } pw.println("\n Condition providers:"); @@ -2970,12 +3046,18 @@ public class NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); + private final ArrayMap<ComponentName, Policy.Token> mPolicyTokens = new ArrayMap<>(); private boolean mNotificationGroupsDesired; public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); } + public Policy.Token getPolicyToken(INotificationListener listener) { + final ManagedServiceInfo info = checkServiceTokenLocked(listener); + return info == null ? null : mPolicyTokens.get(info.component); + } + @Override protected Config getConfig() { Config c = new Config(); @@ -3000,6 +3082,7 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationList) { updateNotificationGroupsDesiredLocked(); update = makeRankingUpdateLocked(info); + mPolicyTokens.put(info.component, new Policy.Token(new Binder())); } try { listener.onListenerConnected(update); @@ -3016,6 +3099,7 @@ public class NotificationManagerService extends SystemService { } mLightTrimListeners.remove(removed); updateNotificationGroupsDesiredLocked(); + mPolicyTokens.remove(removed.component); } public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 40218bb..9cb8af5 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -21,6 +21,7 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import android.app.AppOpsManager; +import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -57,6 +58,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Objects; /** * NotificationManagerService helper for functionality related to zen mode. @@ -230,6 +232,21 @@ public class ZenModeHelper { mConfig.writeXml(out); } + public Policy getNotificationPolicy() { + return getNotificationPolicy(mConfig); + } + + private static Policy getNotificationPolicy(ZenModeConfig config) { + return config == null ? null : config.toNotificationPolicy(); + } + + public void setNotificationPolicy(Policy policy) { + if (policy == null || mConfig == null) return; + final ZenModeConfig newConfig = mConfig.copy(); + newConfig.applyNotificationPolicy(policy); + setConfig(newConfig, "setNotificationPolicy"); + } + public ZenModeConfig getConfig() { return mConfig; } @@ -247,8 +264,13 @@ public class ZenModeHelper { if (config.equals(mConfig)) return true; if (DEBUG) Log.d(TAG, "setConfig reason=" + reason); ZenLog.traceConfig(mConfig, config); + final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig), + getNotificationPolicy(config)); mConfig = config; dispatchOnConfigChanged(); + if (policyChanged){ + dispatchOnPolicyChanged(); + } final String val = Integer.toString(mConfig.hashCode()); Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); if (!evaluateZenMode(reason, setRingerMode)) { @@ -355,6 +377,12 @@ public class ZenModeHelper { } } + private void dispatchOnPolicyChanged() { + for (Callback callback : mCallbacks) { + callback.onPolicyChanged(); + } + } + private void dispatchOnZenModeChanged() { for (Callback callback : mCallbacks) { callback.onZenModeChanged(); @@ -617,6 +645,7 @@ public class ZenModeHelper { public static class Callback { void onConfigChanged() {} void onZenModeChanged() {} + void onPolicyChanged() {} } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 936840a..fce01e5 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -183,6 +183,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; static final int APPLICATION_PANEL_SUBLAYER = 1; static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; + static final int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3; static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; @@ -2015,6 +2016,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return APPLICATION_MEDIA_OVERLAY_SUBLAYER; case TYPE_APPLICATION_SUB_PANEL: return APPLICATION_SUB_PANEL_SUBLAYER; + case TYPE_APPLICATION_ABOVE_SUB_PANEL: + return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER; } Log.e(TAG, "Unknown sub-window type: " + type); return 0; diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 75c33af..1a52933 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -145,6 +145,9 @@ public class KeyguardServiceDelegate { if (mKeyguardState.bootCompleted) { mKeyguardService.onBootCompleted(); } + if (mKeyguardState.occluded) { + mKeyguardService.setOccluded(mKeyguardState.occluded); + } } @Override diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f6df757..184224b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -79,7 +79,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { public void binderDied() { Slog.i(TAG, "binder died for pkg=" + pkg); - disableInternal(userId, 0, token, pkg); + disableForUser(0, token, pkg, userId); token.unlinkToDeath(this, 0); } } @@ -194,10 +194,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void disable(int what, IBinder token, String pkg) { - disableInternal(mCurrentUserId, what, token, pkg); + disableForUser(what, token, pkg, mCurrentUserId); } - private void disableInternal(int userId, int what, IBinder token, String pkg) { + @Override + public void disableForUser(int what, IBinder token, String pkg, int userId) { enforceStatusBar(); synchronized (mLock) { diff --git a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java index 1135dfe..8fc979c 100644 --- a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java +++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java @@ -16,29 +16,21 @@ package com.android.server.updates; +import com.android.server.EventLogTags; + import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.provider.Settings; -import android.util.Base64; import android.util.EventLog; import android.util.Slog; -import com.android.server.EventLogTags; - -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; +import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.Signature; import libcore.io.IoUtils; import libcore.io.Streams; @@ -48,11 +40,8 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { private static final String TAG = "ConfigUpdateInstallReceiver"; private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH"; - private static final String EXTRA_SIGNATURE = "SIGNATURE"; private static final String EXTRA_VERSION_NUMBER = "VERSION"; - private static final String UPDATE_CERTIFICATE_KEY = "config_update_certificate"; - protected final File updateDir; protected final File updateContent; protected final File updateVersion; @@ -71,16 +60,12 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { @Override public void run() { try { - // get the certificate from Settings.Secure - X509Certificate cert = getCert(context.getContentResolver()); // get the content path from the extras byte[] altContent = getAltContent(context, intent); // get the version from the extras int altVersion = getVersionFromIntent(intent); // get the previous value from the extras String altRequiredHash = getRequiredHashFromIntent(intent); - // get the signature from the extras - String altSig = getSignatureFromIntent(intent); // get the version currently being used int currentVersion = getCurrentVersion(); // get the hash of the currently used value @@ -90,10 +75,6 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { } else if (!verifyPreviousHash(currentHash, altRequiredHash)) { EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED, "Current hash did not match required value"); - } else if (!verifySignature(altContent, altVersion, altRequiredHash, altSig, - cert)) { - EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED, - "Signature did not verify"); } else { // install the new content Slog.i(TAG, "Found new update, installing..."); @@ -114,20 +95,6 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { }.start(); } - private X509Certificate getCert(ContentResolver cr) { - // get the cert from settings - String cert = Settings.Secure.getString(cr, UPDATE_CERTIFICATE_KEY); - // convert it into a real certificate - try { - byte[] derCert = Base64.decode(cert.getBytes(), Base64.DEFAULT); - InputStream istream = new ByteArrayInputStream(derCert); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - return (X509Certificate) cf.generateCertificate(istream); - } catch (CertificateException e) { - throw new IllegalStateException("Got malformed certificate from settings, ignoring"); - } - } - private Uri getContentFromIntent(Intent i) { Uri data = i.getData(); if (data == null) { @@ -152,14 +119,6 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { return extraValue.trim(); } - private String getSignatureFromIntent(Intent i) { - String extraValue = i.getStringExtra(EXTRA_SIGNATURE); - if (extraValue == null) { - throw new IllegalStateException("Missing required signature, ignoring."); - } - return extraValue.trim(); - } - private int getCurrentVersion() throws NumberFormatException { try { String strVersion = IoUtils.readFileAsString(updateVersion.getCanonicalPath()).trim(); @@ -215,16 +174,6 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { return current.equals(required); } - private boolean verifySignature(byte[] content, int version, String requiredPrevious, - String signature, X509Certificate cert) throws Exception { - Signature signer = Signature.getInstance("SHA512withRSA"); - signer.initVerify(cert); - signer.update(content); - signer.update(Long.toString(version).getBytes()); - signer.update(requiredPrevious.getBytes()); - return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT)); - } - protected void writeUpdate(File dir, File file, byte[] content) throws IOException { FileOutputStream out = null; File tmp = null; diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index ae8832a..91ce739 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -339,6 +339,7 @@ final class AccessibilityController { case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: case WindowManager.LayoutParams.TYPE_SEARCH_BAR: case WindowManager.LayoutParams.TYPE_PHONE: diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 55dd911..bb53534 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -148,7 +148,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { if (timeout >= 0) { // The activity manager declined to abort dispatching. // Wait a bit longer and timeout again later. - return timeout; + return timeout * 1000000L; // nanoseconds } } catch (RemoteException ex) { } diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 6448de2..a5546cf 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -33,10 +33,12 @@ LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ frameworks/base/services \ frameworks/base/libs \ + frameworks/base/libs/hwui \ frameworks/base/core/jni \ frameworks/native/services \ libcore/include \ libcore/include/libsuspend \ + system/security/keystore/include \ $(call include-path-for, libhardware)/hardware \ $(call include-path-for, libhardware_legacy)/hardware_legacy \ @@ -48,6 +50,7 @@ LOCAL_SHARED_LIBRARIES += \ liblog \ libhardware \ libhardware_legacy \ + libkeystore_binder \ libnativehelper \ libutils \ libui \ diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp index e4f242e..8f4fb51 100644 --- a/services/core/jni/com_android_server_AssetAtlasService.cpp +++ b/services/core/jni/com_android_server_AssetAtlasService.cpp @@ -47,40 +47,9 @@ namespace android { #define FENCE_TIMEOUT 2000000000 // ---------------------------------------------------------------------------- -// JNI Helpers -// ---------------------------------------------------------------------------- - -static struct { - jmethodID setNativeBitmap; -} gCanvasClassInfo; - -#define INVOKEV(object, method, ...) \ - env->CallVoidMethod(object, method, __VA_ARGS__) - -// ---------------------------------------------------------------------------- // Canvas management // ---------------------------------------------------------------------------- -static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject, - jobject canvas, jint width, jint height) { - - SkBitmap* bitmap = new SkBitmap; - bitmap->allocN32Pixels(width, height); - bitmap->eraseColor(0); - INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(bitmap)); - - return reinterpret_cast<jlong>(bitmap); -} - -static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject, - jobject canvas, jlong bitmapHandle) { - - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); - INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0); - - delete bitmap; -} - #define CLEANUP_GL_AND_RETURN(result) \ if (fence != EGL_NO_SYNC_KHR) eglDestroySyncKHR(display, fence); \ if (image) eglDestroyImageKHR(display, image); \ @@ -93,9 +62,12 @@ static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobj return result; static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject, - jobject graphicBuffer, jlong bitmapHandle) { + jobject graphicBuffer, jobject bitmapHandle) { + + SkBitmap bitmap; + GraphicsJNI::getSkBitmap(env, bitmapHandle, &bitmap); + SkAutoLockPixels alp(bitmap); - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); // The goal of this method is to copy the bitmap into the GraphicBuffer // using the GPU to swizzle the texture content sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer)); @@ -186,9 +158,9 @@ static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject } // Upload the content of the bitmap in the GraphicBuffer - glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->width(), bitmap->height(), - GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels()); + glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap.bytesPerPixel()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), + GL_RGBA, GL_UNSIGNED_BYTE, bitmap.getPixels()); if (glGetError() != GL_NO_ERROR) { ALOGW("Could not upload to texture"); CLEANUP_GL_AND_RETURN(JNI_FALSE); @@ -233,20 +205,11 @@ static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject const char* const kClassPathName = "com/android/server/AssetAtlasService"; static JNINativeMethod gMethods[] = { - { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)J", - (void*) com_android_server_AssetAtlasService_acquireCanvas }, - { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;J)V", - (void*) com_android_server_AssetAtlasService_releaseCanvas }, - { "nUploadAtlas", "(Landroid/view/GraphicBuffer;J)Z", + { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z", (void*) com_android_server_AssetAtlasService_upload }, }; int register_android_server_AssetAtlasService(JNIEnv* env) { - jclass clazz; - - FIND_CLASS(clazz, "android/graphics/Canvas"); - GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V"); - return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp index e1c4e27..5a86923 100644 --- a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp +++ b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp @@ -22,12 +22,20 @@ #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <android_os_MessageQueue.h> +#include <binder/IServiceManager.h> +#include <utils/String16.h> +#include <utils/Looper.h> +#include <keystore/IKeystoreService.h> +#include <keystore/keystore.h> // for error code + #include <hardware/hardware.h> #include <hardware/fingerprint.h> +#include <hardware/hw_auth_token.h> + #include <utils/Log.h> -#include <utils/Looper.h> #include "core_jni_helpers.h" + namespace android { static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0); @@ -60,6 +68,23 @@ public: } }; +static void notifyKeystore(uint8_t *auth_token, size_t auth_token_length) { + if (auth_token != NULL && auth_token_length > 0) { + // TODO: cache service? + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("android.security.keystore")); + sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); + if (service != NULL) { + status_t ret = service->addAuthToken(auth_token, auth_token_length); + if (ret != ResponseCode::NO_ERROR) { + ALOGE("Falure sending auth token to KeyStore: %d", ret); + } + } else { + ALOGE("Unable to communicate with KeyStore"); + } + } +} + // Called by the HAL to notify us of fingerprint events static void hal_notify_callback(fingerprint_msg_t msg) { uint32_t arg1 = 0; @@ -72,9 +97,13 @@ static void hal_notify_callback(fingerprint_msg_t msg) { case FINGERPRINT_ACQUIRED: arg1 = msg.data.acquired.acquired_info; break; - case FINGERPRINT_PROCESSED: - arg1 = msg.data.processed.finger.fid; - arg2 = msg.data.processed.finger.gid; + case FINGERPRINT_AUTHENTICATED: + arg1 = msg.data.authenticated.finger.fid; + arg2 = msg.data.authenticated.finger.gid; + if (arg1 != 0) { + notifyKeystore(reinterpret_cast<uint8_t *>(&msg.data.authenticated.hat), + sizeof(msg.data.authenticated.hat)); + } break; case FINGERPRINT_TEMPLATE_ENROLLING: arg1 = msg.data.enroll.finger.fid; @@ -101,15 +130,23 @@ static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callb gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper(); } -static jint nativeEnroll(JNIEnv* env, jobject clazz, jlong challenge, jint groupId, jint timeout) { +static jint nativeEnroll(JNIEnv* env, jobject clazz, jbyteArray token, jint groupId, jint timeout) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout); - int ret = gContext.device->enroll(gContext.device, groupId, timeout); + const int tokenSize = env->GetArrayLength(token); + jbyte* tokenData = env->GetByteArrayElements(token, 0); + if (tokenSize != sizeof(hw_auth_token_t)) { + ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll() : invalid token size %d\n", tokenSize); + return -1; + } + int ret = gContext.device->enroll(gContext.device, + reinterpret_cast<const hw_auth_token_t*>(tokenData), groupId, timeout); + env->ReleaseByteArrayElements(token, tokenData, 0); return reinterpret_cast<jint>(ret); } -static jint nativePreEnroll(JNIEnv* env, jobject clazz) { +static jlong nativePreEnroll(JNIEnv* env, jobject clazz) { uint64_t ret = gContext.device->pre_enroll(gContext.device); - ALOG(LOG_VERBOSE, LOG_TAG, "nativePreEnroll(), result = %" PRId64 "\n", ret); + // ALOG(LOG_VERBOSE, LOG_TAG, "nativePreEnroll(), result = %llx", ret); return reinterpret_cast<jlong>((int64_t)ret); } @@ -125,7 +162,7 @@ static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint return reinterpret_cast<jint>(ret); } -static jint nativeStopAuthentication(JNIEnv* env, jobject clazz, jlong sessionId) { +static jint nativeStopAuthentication(JNIEnv* env, jobject clazz) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeStopAuthentication()\n"); int ret = gContext.device->cancel(gContext.device); return reinterpret_cast<jint>(ret); @@ -194,11 +231,12 @@ static jint nativeCloseHal(JNIEnv* env, jobject clazz) { // ---------------------------------------------------------------------------- + // TODO: clean up void methods static const JNINativeMethod g_methods[] = { { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate }, - { "nativeStopAuthentication", "(J)I", (void*)nativeStopAuthentication }, - { "nativeEnroll", "(JII)I", (void*)nativeEnroll }, + { "nativeStopAuthentication", "()I", (void*)nativeStopAuthentication }, + { "nativeEnroll", "([BII)I", (void*)nativeEnroll }, { "nativePreEnroll", "()J", (void*)nativePreEnroll }, { "nativeStopEnrollment", "()I", (void*)nativeStopEnrollment }, { "nativeRemove", "(II)I", (void*)nativeRemove }, diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp index 852b5e9..2ca5f5a 100644 --- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -31,6 +31,7 @@ static jobject sCallbacksObj = NULL; static JNIEnv *sCallbackEnv = NULL; static hw_device_t* sHardwareDevice = NULL; +static jmethodID sSetVersion = NULL; static jmethodID sOnLocationReport = NULL; static jmethodID sOnDataReport = NULL; static jmethodID sOnBatchingCapabilities = NULL; @@ -141,6 +142,14 @@ static int SetThreadEvent(ThreadEvent event) { } ALOGV("Callback thread attached: %p", sCallbackEnv); + + // Send the version to the upper layer. + sCallbackEnv->CallVoidMethod( + sCallbacksObj, + sSetVersion, + sFlpInterface->size == sizeof(FlpLocationInterface) ? 2 : 1 + ); + CheckExceptions(sCallbackEnv, __FUNCTION__); break; } case DISASSOCIATE_JVM: @@ -176,6 +185,10 @@ static void ClassInit(JNIEnv* env, jclass clazz) { sFlpInterface = NULL; // get references to the Java provider methods + sSetVersion = env->GetMethodID( + clazz, + "setVersion", + "(I)V"); sOnLocationReport = env->GetMethodID( clazz, "onLocationReport", diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c5e1933..e22a2cc 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -32,6 +32,7 @@ import android.app.IActivityManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.StatusBarManager; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; @@ -102,6 +103,7 @@ import android.view.IWindowManager; import com.android.internal.R; import com.android.internal.os.storage.ExternalStorageFormatter; +import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.Preconditions; @@ -152,7 +154,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String DEVICE_POLICIES_XML = "device_policies.xml"; - private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component"; + private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component"; + + private static final String TAG_STATUS_BAR = "statusbar"; + + private static final String ATTR_ENABLED = "enabled"; private static final int REQUEST_EXPIRE_PASSWORD = 5571; @@ -172,6 +178,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; + private static final int STATUS_BAR_DISABLE_MASK = + StatusBarManager.DISABLE_EXPAND | + StatusBarManager.DISABLE_NOTIFICATION_ICONS | + StatusBarManager.DISABLE_NOTIFICATION_ALERTS | + StatusBarManager.DISABLE_SEARCH; + private static final Set<String> DEVICE_OWNER_USER_RESTRICTIONS; static { DEVICE_OWNER_USER_RESTRICTIONS = new HashSet(); @@ -237,6 +249,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Stores and loads state on device and profile owners. private DeviceOwner mDeviceOwner; + private final Binder mToken = new Binder(); + /** * Whether or not device admin feature is supported. If it isn't return defaults for all * public methods. @@ -287,6 +301,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // This is the list of component allowed to start lock task mode. final List<String> mLockTaskPackages = new ArrayList<>(); + boolean mStatusBarEnabledState = true; + ComponentName mRestrictionsProvider; String mDelegatedCertInstallerPackage; @@ -1429,9 +1445,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (int i=0; i<policy.mLockTaskPackages.size(); i++) { String component = policy.mLockTaskPackages.get(i); - out.startTag(null, LOCK_TASK_COMPONENTS_XML); + out.startTag(null, TAG_LOCK_TASK_COMPONENTS); out.attribute(null, "name", component); - out.endTag(null, LOCK_TASK_COMPONENTS_XML); + out.endTag(null, TAG_LOCK_TASK_COMPONENTS); + } + + if (!policy.mStatusBarEnabledState) { + out.startTag(null, TAG_STATUS_BAR); + out.attribute(null, ATTR_ENABLED, Boolean.toString(policy.mStatusBarEnabledState)); + out.endTag(null, TAG_STATUS_BAR); } out.endTag(null, "policies"); @@ -1552,9 +1574,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mActivePasswordNonLetter = Integer.parseInt( parser.getAttributeValue(null, "nonletter")); XmlUtils.skipCurrentTag(parser); - } else if (LOCK_TASK_COMPONENTS_XML.equals(tag)) { + } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); XmlUtils.skipCurrentTag(parser); + } else if (TAG_STATUS_BAR.equals(tag)) { + policy.mStatusBarEnabledState = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_ENABLED)); + XmlUtils.skipCurrentTag(parser); } else { Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -1612,10 +1638,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void updateLockTaskPackagesLocked(DevicePolicyData policy, int userId) { IActivityManager am = ActivityManagerNative.getDefault(); + long ident = Binder.clearCallingIdentity(); try { am.updateLockTaskPackages(userId, policy.mLockTaskPackages.toArray(new String[0])); } catch (RemoteException e) { // Not gonna happen. + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -1679,7 +1708,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return; } - getUserData(UserHandle.USER_OWNER); + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); loadDeviceOwner(); cleanUpOldUsers(); // Register an observer for watching for user setup complete. @@ -1696,6 +1725,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getScreenCaptureDisabled(null, userHandle)); } + if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner() + && !policy.mStatusBarEnabledState) { + setStatusBarEnabledStateInternal(STATUS_BAR_DISABLE_MASK, UserHandle.USER_OWNER); + } } private void cleanUpOldUsers() { @@ -5817,12 +5850,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int userId = UserHandle.getCallingUserId(); LockPatternUtils utils = new LockPatternUtils(mContext); - // disallow disabling the keyguard if a password is currently set - if (!enabled && utils.isSecure(userId)) { - return false; - } long ident = Binder.clearCallingIdentity(); try { + // disallow disabling the keyguard if a password is currently set + if (!enabled && utils.isSecure(userId)) { + return false; + } utils.setLockScreenDisabled(!enabled, userId); } finally { Binder.restoreCallingIdentity(ident); @@ -5830,6 +5863,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return true; } + @Override + public void setStatusBarEnabledState(ComponentName who, boolean enabled) { + 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 ? StatusBarManager.DISABLE_NONE : STATUS_BAR_DISABLE_MASK, + userId); + saveSettingsLocked(userId); + } + } + } + + private void setStatusBarEnabledStateInternal(int flags, int userId) { + long ident = Binder.clearCallingIdentity(); + try { + IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); + if (statusBarService != null) { + statusBarService.disableForUser(flags, mToken, + mDeviceOwner.getDeviceOwnerPackageName(), userId); + } + } catch (RemoteException e) { + Slog.e(LOG_TAG, "Failed to disable the status bar", e); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + /** * We need to update the internal state of whether a user has completed setup once. After * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 8a28d51..7dce83e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -393,12 +393,9 @@ public class VoiceInteractionManagerService extends SystemService { throw new SecurityException( "Caller is not the current voice interaction service"); } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.showSessionLocked(callingPid, callingUid, args, flags, - null /* showCallback */); + mImpl.showSessionLocked(args, flags, null /* showCallback */); } finally { Binder.restoreCallingIdentity(caller); } @@ -432,12 +429,9 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "showSessionFromSession without running voice interaction service"); return false; } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags, - null /* showCallback */); + return mImpl.showSessionLocked(sessionArgs, flags, null /* showCallback */); } finally { Binder.restoreCallingIdentity(caller); } @@ -506,11 +500,9 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "finish without running voice interaction service"); return; } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.finishLocked(callingPid, callingUid, token); + mImpl.finishLocked(token); } finally { Binder.restoreCallingIdentity(caller); } @@ -708,11 +700,9 @@ public class VoiceInteractionManagerService extends SystemService { + "service"); return; } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.showSessionLocked(callingPid, callingUid, new Bundle() /* sessionArgs */, + mImpl.showSessionLocked(new Bundle() /* sessionArgs */, VoiceInteractionService.START_SOURCE_ASSIST_GESTURE | VoiceInteractionService.START_WITH_ASSIST | VoiceInteractionService.START_WITH_SCREENSHOT, diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index bca757b..61ec162 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -135,11 +135,11 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mContext.registerReceiver(mBroadcastReceiver, filter, null, handler); } - public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags, + public boolean showSessionLocked(Bundle args, int flags, IVoiceInteractionSessionShowCallback showCallback) { if (mActiveSession == null) { mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName, - mUser, mContext, this, callingPid, callingUid); + mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid); } return mActiveSession.showLocked(args, flags, showCallback); } @@ -196,7 +196,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - public void finishLocked(int callingPid, int callingUid, IBinder token) { + public void finishLocked(IBinder token) { if (mActiveSession == null || token != mActiveSession.mToken) { Slog.w(TAG, "finish does not match active session"); return; @@ -267,7 +267,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne @Override public void sessionConnectionGone(VoiceInteractionSessionConnection connection) { synchronized (mLock) { - finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken); + finishLocked(connection.mToken); } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index fb83956..9634ab8 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -59,7 +59,6 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { final int mUser; final Context mContext; final Callback mCallback; - final int mCallingPid; final int mCallingUid; final IActivityManager mAm; final IWindowManager mIWindowManager; @@ -139,13 +138,12 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { }; public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user, - Context context, Callback callback, int callingPid, int callingUid) { + Context context, Callback callback, int callingUid) { mLock = lock; mSessionComponentName = component; mUser = user; mContext = context; mCallback = callback; - mCallingPid = callingPid; mCallingUid = callingUid; mAm = ActivityManagerNative.getDefault(); mIWindowManager = IWindowManager.Stub.asInterface( |