Merge changes Id71b4cbc,I8dff0a12,Ife3d1390 into rvc-dev

* changes:
  Add startDreamActivity request verification
  Make DreamService use an Activity
  Clean up dreamland
This commit is contained in:
Galia Peycheva
2020-02-25 10:11:21 +00:00
committed by Android (Google) Code Review
11 changed files with 325 additions and 193 deletions

View File

@@ -98,6 +98,14 @@ interface IActivityTaskManager {
in ProfilerInfo profilerInfo, in Bundle options, int userId);
boolean startNextMatchingActivity(in IBinder callingActivity,
in Intent intent, in Bundle options);
/**
* The DreamActivity has to be started in a special way that does not involve the PackageParser.
* The DreamActivity is a framework component inserted in the dream application process. Hence,
* it is not declared in the application's manifest and cannot be parsed. startDreamActivity
* creates the activity and starts it without reaching out to the PackageParser.
*/
boolean startDreamActivity(in Intent intent);
int startActivityIntentSender(in IApplicationThread caller,
in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.service.dreams;
import android.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
/**
* The Activity used by the {@link DreamService} to draw screensaver content
* on the screen. This activity runs in dream application's process, but is started by a
* specialized method: {@link com.android.server.wm.ActivityTaskManagerService#startDreamActivity}.
* Hence, it does not have to be declared in the dream application's manifest.
*
* We use an activity as the dream canvas, because it interacts easier with other activities on
* the screen (compared to a hover window). However, the DreamService is in charge of the dream and
* it receives all Window.Callbacks from its main window. Since a window can have only one callback
* receiver, the activity will not receive any window callbacks.
*
* Prior to the DreamActivity, the DreamService used to work with a hovering window and give the
* screensaver application control over that window. The DreamActivity is a replacement to that
* hover window. Using an activity allows for better-defined interactions with the rest of the
* activities on screen. The switch to DreamActivity should be transparent to the screensaver
* application, i.e. the application will still use DreamService APIs and not notice that the
* system is using an activity behind the scenes.
*
* @hide
*/
public class DreamActivity extends Activity {
static final String EXTRA_CALLBACK = "binder";
public DreamActivity() {}
@Override
public void onCreate(@Nullable Bundle bundle) {
super.onCreate(bundle);
DreamService.DreamServiceWrapper callback =
(DreamService.DreamServiceWrapper) getIntent().getIBinderExtra(EXTRA_CALLBACK);
if (callback != null) {
callback.onActivityCreated(this);
}
}
}

View File

@@ -16,6 +16,8 @@
package android.service.dreams;
import android.content.ComponentName;
/**
* Dream manager local system service interface.
*
@@ -42,4 +44,13 @@ public abstract class DreamManagerInternal {
* Called by the power manager to determine whether a dream is running.
*/
public abstract boolean isDreaming();
/**
* Called by the ActivityTaskManagerService to verify that the startDreamActivity
* request comes from the current active dream component.
*
* @param doze If true returns the current active doze component. Otherwise, returns the
* active dream component.
*/
public abstract ComponentName getActiveDreamComponent(boolean doze);
}

View File

@@ -15,25 +15,29 @@
*/
package android.service.dreams;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.view.ActionMode;
@@ -48,10 +52,8 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils.Dump;
@@ -176,10 +178,11 @@ public class DreamService extends Service implements Window.Callback {
*/
public static final String DREAM_META_DATA = "android.service.dream";
private final IDreamManager mSandman;
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private final IDreamManager mDreamManager;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private IBinder mDreamToken;
private Window mWindow;
private Activity mActivity;
private boolean mInteractive;
private boolean mLowProfile = true;
private boolean mFullscreen;
@@ -195,8 +198,11 @@ public class DreamService extends Service implements Window.Callback {
private boolean mDebug = false;
private DreamServiceWrapper mDreamServiceWrapper;
private Runnable mDispatchAfterOnAttachedToWindow;
public DreamService() {
mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
}
/**
@@ -602,6 +608,8 @@ public class DreamService extends Service implements Window.Callback {
* Marks this dream as windowless. Only available to doze dreams.
*
* @hide
*
* TODO: Remove @UnsupportedAppUsage.
*/
@UnsupportedAppUsage
public void setWindowless(boolean windowless) {
@@ -670,14 +678,14 @@ public class DreamService extends Service implements Window.Callback {
}
private void updateDoze() {
if (mWindowToken == null) {
Slog.w(TAG, "Updating doze without a window token.");
if (mDreamToken == null) {
Slog.w(TAG, "Updating doze without a dream token.");
return;
}
if (mDozing) {
try {
mSandman.startDozing(mWindowToken, mDozeScreenState, mDozeScreenBrightness);
mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
} catch (RemoteException ex) {
// system server died
}
@@ -700,7 +708,7 @@ public class DreamService extends Service implements Window.Callback {
if (mDozing) {
mDozing = false;
try {
mSandman.stopDozing(mWindowToken);
mDreamManager.stopDozing(mDreamToken);
} catch (RemoteException ex) {
// system server died
}
@@ -875,14 +883,15 @@ public class DreamService extends Service implements Window.Callback {
* </p>
*/
public void onWakeUp() {
finish();
mActivity.finishAndRemoveTask();
}
/** {@inheritDoc} */
@Override
public final IBinder onBind(Intent intent) {
if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
return new DreamServiceWrapper();
mDreamServiceWrapper = new DreamServiceWrapper();
return mDreamServiceWrapper;
}
/**
@@ -895,20 +904,25 @@ public class DreamService extends Service implements Window.Callback {
public final void finish() {
if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished);
if (mActivity == null) {
Slog.w(TAG, "Finish was called before the dream was attached.");
} else if (!mActivity.isFinishing()) {
// In case the activity is not finished yet, do it now. This can happen if someone calls
// finish() directly, without going through wakeUp().
mActivity.finishAndRemoveTask();
return;
}
if (!mFinished) {
mFinished = true;
if (mWindowToken == null) {
Slog.w(TAG, "Finish was called before the dream was attached.");
} else {
try {
mSandman.finishSelf(mWindowToken, true /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
try {
// finishSelf will unbind the dream controller from the dream service. This will
// trigger DreamService.this.onDestroy and DreamService.this will die.
mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
stopSelf(); // if launched via any other means
}
}
@@ -938,11 +952,11 @@ public class DreamService extends Service implements Window.Callback {
// Now tell the system we are waking gently, unless we already told
// it we were finishing immediately.
if (!fromSystem && !mFinished) {
if (mWindowToken == null) {
if (mActivity == null) {
Slog.w(TAG, "WakeUp was called before the dream was attached.");
} else {
try {
mSandman.finishSelf(mWindowToken, false /*immediate*/);
mDreamManager.finishSelf(mDreamToken, false /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
@@ -977,20 +991,14 @@ public class DreamService extends Service implements Window.Callback {
onDreamingStopped();
}
if (mWindow != null) {
// force our window to be removed synchronously
if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
mWindow = null;
if (mActivity != null && !mActivity.isFinishing()) {
mActivity.finishAndRemoveTask();
} else {
finish();
}
if (mWindowToken != null) {
// the following will print a log message if it finds any other leaked windows
WindowManagerGlobal.getInstance().closeAll(mWindowToken,
this.getClass().getName(), "Dream");
mWindowToken = null;
mCanDoze = false;
}
mDreamToken = null;
mCanDoze = false;
}
/**
@@ -998,95 +1006,107 @@ public class DreamService extends Service implements Window.Callback {
*
* Must run on mHandler.
*
* @param windowToken A window token that will allow a window to be created in the correct layer.
* @param dreamToken Token for this dream service.
* @param started A callback that will be invoked once onDreamingStarted has completed.
*/
private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
if (mWindowToken != null) {
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
if (mActivity != null) {
Slog.e(TAG, "attach() called when dream with token=" + mDreamToken
+ " already attached");
return;
}
if (mFinished || mWaking) {
Slog.w(TAG, "attach() called after dream already finished");
try {
mSandman.finishSelf(windowToken, true /*immediate*/);
mDreamManager.finishSelf(dreamToken, true /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
return;
}
mWindowToken = windowToken;
mDreamToken = dreamToken;
mCanDoze = canDoze;
if (mWindowless && !mCanDoze) {
throw new IllegalStateException("Only doze dreams can be windowless");
}
if (!mWindowless) {
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_DREAM;
lp.token = windowToken;
lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
// Workaround: Currently low-profile and in-window system bar backgrounds don't go
// along well. Dreams usually don't need such bars anyways, so disable them by default.
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
mWindow.setWindowManager(null, windowToken, "dream", true);
applySystemUiVisibilityFlags(
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
View.SYSTEM_UI_FLAG_LOW_PROFILE);
try {
getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
} catch (WindowManager.BadTokenException ex) {
// This can happen because the dream manager service will remove the token
// immediately without necessarily waiting for the dream to start.
// We should receive a finish message soon.
Slog.i(TAG, "attach() called after window token already removed, dream will "
+ "finish soon");
mWindow = null;
return;
}
}
// We need to defer calling onDreamingStarted until after onWindowAttached,
// which is posted to the handler by addView, so we post onDreamingStarted
// to the handler also. Need to watch out here in case detach occurs before
// this callback is invoked.
mHandler.post(new Runnable() {
@Override
public void run() {
if (mWindow != null || mWindowless) {
if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
mStarted = true;
mDispatchAfterOnAttachedToWindow = () -> {
if (mWindow != null || mWindowless) {
mStarted = true;
try {
onDreamingStarted();
} finally {
try {
onDreamingStarted();
} finally {
try {
started.sendResult(null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
started.sendResult(null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
};
// We need to defer calling onDreamingStarted until after the activity is created.
// If the dream is windowless, we can call it immediately. Otherwise, we wait
// for the DreamActivity to report onActivityCreated via
// DreamServiceWrapper.onActivityCreated.
if (!mWindowless) {
Intent i = new Intent(this, DreamActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
try {
if (!ActivityTaskManager.getService().startDreamActivity(i)) {
detach();
return;
}
} catch (RemoteException e) {
Log.w(TAG, "Could not connect to activity task manager to start dream activity");
e.rethrowFromSystemServer();
}
} else {
mDispatchAfterOnAttachedToWindow.run();
}
}
private void onWindowCreated(Window w) {
mWindow = w;
mWindow.setCallback(this);
mWindow.setType(TYPE_DREAM);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
// Workaround: Currently low-profile and in-window system bar backgrounds don't go
// along well. Dreams usually don't need such bars anyways, so disable them by default.
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
applySystemUiVisibilityFlags(
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
View.SYSTEM_UI_FLAG_LOW_PROFILE);
mWindow.getDecorView().addOnAttachStateChangeListener(
new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
mDispatchAfterOnAttachedToWindow.run();
}
@Override
public void onViewDetachedFromWindow(View v) {
finish();
}
});
}
private boolean getWindowFlagValue(int flag, boolean defaultValue) {
@@ -1131,10 +1151,10 @@ public class DreamService extends Service implements Window.Callback {
/** @hide */
protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(TAG + ": ");
if (mWindowToken == null) {
if (mFinished) {
pw.println("stopped");
} else {
pw.println("running (token=" + mWindowToken + ")");
pw.println("running (dreamToken=" + mDreamToken + ")");
}
pw.println(" window: " + mWindow);
pw.print(" flags:");
@@ -1156,36 +1176,32 @@ public class DreamService extends Service implements Window.Callback {
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
private final class DreamServiceWrapper extends IDreamService.Stub {
/**
* The DreamServiceWrapper is used as a gateway to the system_server, where DreamController
* uses it to control the DreamService. It is also used to receive callbacks from the
* DreamActivity.
*/
final class DreamServiceWrapper extends IDreamService.Stub {
@Override
public void attach(final IBinder windowToken, final boolean canDoze,
public void attach(final IBinder dreamToken, final boolean canDoze,
IRemoteCallback started) {
mHandler.post(new Runnable() {
@Override
public void run() {
DreamService.this.attach(windowToken, canDoze, started);
}
});
mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started));
}
@Override
public void detach() {
mHandler.post(new Runnable() {
@Override
public void run() {
DreamService.this.detach();
}
});
mHandler.post(DreamService.this::detach);
}
@Override
public void wakeUp() {
mHandler.post(new Runnable() {
@Override
public void run() {
DreamService.this.wakeUp(true /*fromSystem*/);
}
});
mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
}
/** @hide */
void onActivityCreated(DreamActivity a) {
mActivity = a;
onWindowCreated(a.getWindow());
}
}
}

View File

@@ -1612,6 +1612,7 @@
<java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
<java-symbol type="style" name="Theme.IconMenu" />
<java-symbol type="style" name="Theme.Dream" />
<java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" />
<java-symbol type="style" name="Pointer" />
<java-symbol type="style" name="LargePointer" />

View File

@@ -701,6 +701,11 @@ please see themes_device_defaults.xml.
<item name="windowNoDisplay">true</item>
</style>
<style name="Theme.Dream">
<item name="windowBackground">@null</item>
<item name="windowDisablePreview">true</item>
</style>
<!-- Default theme for dialog windows and activities (on API level 10 and lower),
which is used by the
{@link android.app.Dialog} class. This changes the window to be

View File

@@ -16,9 +16,6 @@
package com.android.server.dreams;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -27,10 +24,10 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.IRemoteCallback;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.IBinder.DeathRecipient;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
@@ -38,15 +35,14 @@ import android.service.dreams.DreamService;
import android.service.dreams.IDreamService;
import android.util.Slog;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.io.PrintWriter;
import java.util.NoSuchElementException;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
/**
* Internal controller for starting and stopping the current dream and managing related state.
*
@@ -86,12 +82,9 @@ final class DreamController {
}
};
private final Runnable mStopStubbornDreamRunnable = new Runnable() {
@Override
public void run() {
Slog.w(TAG, "Stubborn dream did not finish itself in the time allotted");
stopDream(true /*immediate*/);
}
private final Runnable mStopStubbornDreamRunnable = () -> {
Slog.w(TAG, "Stubborn dream did not finish itself in the time allotted");
stopDream(true /*immediate*/);
};
public DreamController(Context context, Handler handler, Listener listener) {
@@ -140,14 +133,6 @@ final class DreamController {
MetricsLogger.visible(mContext,
mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
try {
mIWindowManager.addWindowToken(token, TYPE_DREAM, DEFAULT_DISPLAY);
} catch (RemoteException ex) {
Slog.e(TAG, "Unable to add window token for dream.", ex);
stopDream(true /*immediate*/);
return;
}
Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -216,9 +201,6 @@ final class DreamController {
}
if (oldDream.mService != null) {
// Tell the dream that it's being stopped so that
// it can shut down nicely before we yank its window token out from
// under it.
try {
oldDream.mService.detach();
} catch (RemoteException ex) {
@@ -238,18 +220,7 @@ final class DreamController {
}
oldDream.releaseWakeLockIfNeeded();
try {
mIWindowManager.removeWindowToken(oldDream.mToken, DEFAULT_DISPLAY);
} catch (RemoteException ex) {
Slog.w(TAG, "Error removing window token for dream.", ex);
}
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDreamStopped(oldDream.mToken);
}
});
mHandler.post(() -> mListener.onDreamStopped(oldDream.mToken));
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -313,13 +284,10 @@ final class DreamController {
// May be called on any thread.
@Override
public void binderDied() {
mHandler.post(new Runnable() {
@Override
public void run() {
mService = null;
if (mCurrentDream == DreamRecord.this) {
stopDream(true /*immediate*/);
}
mHandler.post(() -> {
mService = null;
if (mCurrentDream == DreamRecord.this) {
stopDream(true /*immediate*/);
}
});
}
@@ -327,16 +295,13 @@ final class DreamController {
// May be called on any thread.
@Override
public void onServiceConnected(ComponentName name, final IBinder service) {
mHandler.post(new Runnable() {
@Override
public void run() {
mConnected = true;
if (mCurrentDream == DreamRecord.this && mService == null) {
attach(IDreamService.Stub.asInterface(service));
// Wake lock will be released once dreaming starts.
} else {
releaseWakeLockIfNeeded();
}
mHandler.post(() -> {
mConnected = true;
if (mCurrentDream == DreamRecord.this && mService == null) {
attach(IDreamService.Stub.asInterface(service));
// Wake lock will be released once dreaming starts.
} else {
releaseWakeLockIfNeeded();
}
});
}
@@ -344,13 +309,10 @@ final class DreamController {
// May be called on any thread.
@Override
public void onServiceDisconnected(ComponentName name) {
mHandler.post(new Runnable() {
@Override
public void run() {
mService = null;
if (mCurrentDream == DreamRecord.this) {
stopDream(true /*immediate*/);
}
mHandler.post(() -> {
mService = null;
if (mCurrentDream == DreamRecord.this) {
stopDream(true /*immediate*/);
}
});
}
@@ -373,4 +335,4 @@ final class DreamController {
}
};
}
}
}

View File

@@ -268,6 +268,10 @@ public final class DreamManagerService extends SystemService {
}
}
private ComponentName getActiveDreamComponentInternal(boolean doze) {
return chooseDreamForUser(doze, ActivityManager.getCurrentUser());
}
private ComponentName chooseDreamForUser(boolean doze, int userId) {
if (doze) {
ComponentName dozeComponent = getDozeComponent(userId);
@@ -671,6 +675,11 @@ public final class DreamManagerService extends SystemService {
public boolean isDreaming() {
return isDreamingInternal();
}
@Override
public ComponentName getActiveDreamComponent(boolean doze) {
return getActiveDreamComponentInternal(doze);
}
}
private final Runnable mSystemPropertiesChanged = new Runnable() {

View File

@@ -335,6 +335,7 @@ class ActivityStarter {
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
boolean allowBackgroundActivityStart;
boolean isDream;
/**
* If set to {@code true}, allows this activity start to look into
@@ -386,6 +387,7 @@ class ActivityStarter {
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
allowBackgroundActivityStart = false;
isDream = false;
}
/**
@@ -426,6 +428,7 @@ class ActivityStarter {
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
allowBackgroundActivityStart = request.allowBackgroundActivityStart;
isDream = request.isDream;
}
/**
@@ -969,7 +972,7 @@ class ActivityStarter {
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
intent);
request.isDream, intent);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
@@ -1179,13 +1182,18 @@ class ActivityStarter {
boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, int realCallingPid,
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart, Intent intent) {
boolean allowBackgroundActivityStart, boolean isDream, Intent intent) {
// don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid);
if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
|| callingAppId == Process.NFC_UID) {
return false;
}
// don't abort if this is the dream activity
if (isDream) {
return false;
}
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow =
@@ -2669,6 +2677,11 @@ class ActivityStarter {
return this;
}
ActivityStarter setIsDream(boolean isDream) {
mRequest.isDream = isDream;
return this;
}
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
pw.print(prefix);

View File

@@ -212,6 +212,8 @@ import android.os.WorkSource;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.sysprop.DisplayProperties;
@@ -1230,6 +1232,52 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
@Override
public boolean startDreamActivity(Intent intent) {
final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
final long origId = Binder.clearCallingIdentity();
// The dream activity is only called for non-doze dreams.
final ComponentName currentDream = LocalServices.getService(DreamManagerInternal.class)
.getActiveDreamComponent(/* doze= */ false);
if (currentDream == null || currentDream.getPackageName() == null
|| !currentDream.getPackageName().equals(process.mInfo.packageName)) {
Slog.e(TAG, "Calling package is not the current dream package. "
+ "Aborting startDreamActivity...");
return false;
}
final ActivityInfo a = new ActivityInfo();
a.theme = com.android.internal.R.style.Theme_Dream;
a.exported = true;
a.name = DreamActivity.class.getName();
a.packageName = process.mInfo.packageName;
a.applicationInfo = process.mInfo;
a.processName = process.mInfo.processName;
a.uiOptions = process.mInfo.uiOptions;
a.taskAffinity = "android:" + a.packageName + "/dream";
a.enabled = true;
a.launchMode = ActivityInfo.LAUNCH_SINGLE_INSTANCE;
a.persistableMode = ActivityInfo.PERSIST_NEVER;
a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
try {
getActivityStartController().obtainStarter(intent, "dream")
.setActivityInfo(a)
.setIsDream(true)
.execute();
return true;
} finally {
Binder.restoreCallingIdentity(origId);
}
}
@Override
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
@@ -2403,7 +2451,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final ActivityStarter starter = getActivityStartController().obtainStarter(
null /* intent */, "moveTaskToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
-1, callerApp, null, false, null)) {
-1, callerApp, null, false, false, null)) {
if (!isBackgroundActivityStartsEnabled()) {
return;
}

View File

@@ -111,7 +111,7 @@ class AppTaskImpl extends IAppTask.Stub {
final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
null /* intent */, "moveToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
callingPackage, -1, -1, callerApp, null, false, null)) {
callingPackage, -1, -1, callerApp, null, false, false, null)) {
if (!mService.isBackgroundActivityStartsEnabled()) {
return;
}