DisplayManagerService.java revision 4504de5d5a8e1c7dfb306b16282f348856c24764
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.display;
18
19import com.android.internal.util.IndentingPrintWriter;
20
21import android.Manifest;
22import android.content.Context;
23import android.content.pm.PackageManager;
24import android.hardware.display.DisplayManager;
25import android.hardware.display.DisplayManagerGlobal;
26import android.hardware.display.IDisplayManager;
27import android.hardware.display.IDisplayManagerCallback;
28import android.hardware.display.WifiDisplayStatus;
29import android.os.Binder;
30import android.os.Handler;
31import android.os.IBinder;
32import android.os.Looper;
33import android.os.Message;
34import android.os.Process;
35import android.os.RemoteException;
36import android.os.SystemClock;
37import android.os.SystemProperties;
38import android.text.TextUtils;
39import android.util.Log;
40import android.util.Slog;
41import android.util.SparseArray;
42import android.view.Display;
43import android.view.DisplayInfo;
44import android.view.Surface;
45
46import com.android.server.UiThread;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.concurrent.CopyOnWriteArrayList;
53
54/**
55 * Manages attached displays.
56 * <p>
57 * The {@link DisplayManagerService} manages the global lifecycle of displays,
58 * decides how to configure logical displays based on the physical display devices currently
59 * attached, sends notifications to the system and to applications when the state
60 * changes, and so on.
61 * </p><p>
62 * The display manager service relies on a collection of {@link DisplayAdapter} components,
63 * for discovering and configuring physical display devices attached to the system.
64 * There are separate display adapters for each manner that devices are attached:
65 * one display adapter for built-in local displays, one for simulated non-functional
66 * displays when the system is headless, one for simulated overlay displays used for
67 * development, one for wifi displays, etc.
68 * </p><p>
69 * Display adapters are only weakly coupled to the display manager service.
70 * Display adapters communicate changes in display device state to the display manager
71 * service asynchronously via a {@link DisplayAdapter.Listener} registered
72 * by the display manager service.  This separation of concerns is important for
73 * two main reasons.  First, it neatly encapsulates the responsibilities of these
74 * two classes: display adapters handle individual display devices whereas
75 * the display manager service handles the global state.  Second, it eliminates
76 * the potential for deadlocks resulting from asynchronous display device discovery.
77 * </p>
78 *
79 * <h3>Synchronization</h3>
80 * <p>
81 * Because the display manager may be accessed by multiple threads, the synchronization
82 * story gets a little complicated.  In particular, the window manager may call into
83 * the display manager while holding a surface transaction with the expectation that
84 * it can apply changes immediately.  Unfortunately, that means we can't just do
85 * everything asynchronously (*grump*).
86 * </p><p>
87 * To make this work, all of the objects that belong to the display manager must
88 * use the same lock.  We call this lock the synchronization root and it has a unique
89 * type {@link DisplayManagerService.SyncRoot}.  Methods that require this lock are
90 * named with the "Locked" suffix.
91 * </p><p>
92 * Where things get tricky is that the display manager is not allowed to make
93 * any potentially reentrant calls, especially into the window manager.  We generally
94 * avoid this by making all potentially reentrant out-calls asynchronous.
95 * </p>
96 */
97public final class DisplayManagerService extends IDisplayManager.Stub {
98    private static final String TAG = "DisplayManagerService";
99    private static final boolean DEBUG = false;
100
101    // When this system property is set to 0, WFD is forcibly disabled on boot.
102    // When this system property is set to 1, WFD is forcibly enabled on boot.
103    // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
104    private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
105
106    private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
107
108    private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
109    private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
110    private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
111    private static final int MSG_REQUEST_TRAVERSAL = 4;
112    private static final int MSG_UPDATE_VIEWPORT = 5;
113
114    private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
115    private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
116    private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
117
118    private final Context mContext;
119    private final DisplayManagerHandler mHandler;
120    private final Handler mUiHandler;
121    private final DisplayAdapterListener mDisplayAdapterListener;
122    private WindowManagerFuncs mWindowManagerFuncs;
123    private InputManagerFuncs mInputManagerFuncs;
124
125    // The synchronization root for the display manager.
126    // This lock guards most of the display manager's state.
127    // NOTE: This is synchronized on while holding WindowManagerService.mWindowMap so never call
128    // into WindowManagerService methods that require mWindowMap while holding this unless you are
129    // very very sure that no deadlock can occur.
130    private final SyncRoot mSyncRoot = new SyncRoot();
131
132    // True if in safe mode.
133    // This option may disable certain display adapters.
134    public boolean mSafeMode;
135
136    // True if we are in a special boot mode where only core applications and
137    // services should be started.  This option may disable certain display adapters.
138    public boolean mOnlyCore;
139
140    // True if the display manager service should pretend there is only one display
141    // and only tell applications about the existence of the default logical display.
142    // The display manager can still mirror content to secondary displays but applications
143    // cannot present unique content on those displays.
144    // Used for demonstration purposes only.
145    private final boolean mSingleDisplayDemoMode;
146
147    // All callback records indexed by calling process id.
148    public final SparseArray<CallbackRecord> mCallbacks =
149            new SparseArray<CallbackRecord>();
150
151    // List of all currently registered display adapters.
152    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
153
154    // List of all currently connected display devices.
155    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
156
157    // List of all logical displays indexed by logical display id.
158    private final SparseArray<LogicalDisplay> mLogicalDisplays =
159            new SparseArray<LogicalDisplay>();
160    private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
161
162    // List of all display transaction listeners.
163    private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
164            new CopyOnWriteArrayList<DisplayTransactionListener>();
165
166    // Set to true if all displays have been blanked by the power manager.
167    private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
168
169    // Set to true when there are pending display changes that have yet to be applied
170    // to the surface flinger state.
171    private boolean mPendingTraversal;
172
173    // The Wifi display adapter, or null if not registered.
174    private WifiDisplayAdapter mWifiDisplayAdapter;
175
176    // The number of active wifi display scan requests.
177    private int mWifiDisplayScanRequestCount;
178
179    // The virtual display adapter, or null if not registered.
180    private VirtualDisplayAdapter mVirtualDisplayAdapter;
181
182    // Viewports of the default display and the display that should receive touch
183    // input from an external source.  Used by the input system.
184    private final DisplayViewport mDefaultViewport = new DisplayViewport();
185    private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
186
187    // Persistent data store for all internal settings maintained by the display manager service.
188    private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
189
190    // Temporary callback list, used when sending display events to applications.
191    // May be used outside of the lock but only on the handler thread.
192    private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
193
194    // Temporary display info, used for comparing display configurations.
195    private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
196
197    // Temporary viewports, used when sending new viewport information to the
198    // input system.  May be used outside of the lock but only on the handler thread.
199    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
200    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
201
202    public DisplayManagerService(Context context, Handler mainHandler) {
203        mContext = context;
204        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
205        mUiHandler = UiThread.getHandler();
206        mDisplayAdapterListener = new DisplayAdapterListener();
207        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
208
209        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
210    }
211
212    /**
213     * Pauses the boot process to wait for the first display to be initialized.
214     */
215    public boolean waitForDefaultDisplay() {
216        synchronized (mSyncRoot) {
217            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
218            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
219                long delay = timeout - SystemClock.uptimeMillis();
220                if (delay <= 0) {
221                    return false;
222                }
223                if (DEBUG) {
224                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
225                }
226                try {
227                    mSyncRoot.wait(delay);
228                } catch (InterruptedException ex) {
229                }
230            }
231        }
232        return true;
233    }
234
235    /**
236     * Called during initialization to associate the display manager with the
237     * window manager.
238     */
239    public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
240        synchronized (mSyncRoot) {
241            mWindowManagerFuncs = windowManagerFuncs;
242            scheduleTraversalLocked(false);
243        }
244    }
245
246    /**
247     * Called during initialization to associate the display manager with the
248     * input manager.
249     */
250    public void setInputManager(InputManagerFuncs inputManagerFuncs) {
251        synchronized (mSyncRoot) {
252            mInputManagerFuncs = inputManagerFuncs;
253            scheduleTraversalLocked(false);
254        }
255    }
256
257    /**
258     * Called when the system is ready to go.
259     */
260    public void systemReady(boolean safeMode, boolean onlyCore) {
261        synchronized (mSyncRoot) {
262            mSafeMode = safeMode;
263            mOnlyCore = onlyCore;
264        }
265
266        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
267    }
268
269    /**
270     * Registers a display transaction listener to provide the client a chance to
271     * update its surfaces within the same transaction as any display layout updates.
272     *
273     * @param listener The listener to register.
274     */
275    public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
276        if (listener == null) {
277            throw new IllegalArgumentException("listener must not be null");
278        }
279
280        // List is self-synchronized copy-on-write.
281        mDisplayTransactionListeners.add(listener);
282    }
283
284    /**
285     * Unregisters a display transaction listener to provide the client a chance to
286     * update its surfaces within the same transaction as any display layout updates.
287     *
288     * @param listener The listener to unregister.
289     */
290    public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
291        if (listener == null) {
292            throw new IllegalArgumentException("listener must not be null");
293        }
294
295        // List is self-synchronized copy-on-write.
296        mDisplayTransactionListeners.remove(listener);
297    }
298
299    /**
300     * Overrides the display information of a particular logical display.
301     * This is used by the window manager to control the size and characteristics
302     * of the default display.  It is expected to apply the requested change
303     * to the display information synchronously so that applications will immediately
304     * observe the new state.
305     *
306     * NOTE: This method must be the only entry point by which the window manager
307     * influences the logical configuration of displays.
308     *
309     * @param displayId The logical display id.
310     * @param info The new data to be stored.
311     */
312    public void setDisplayInfoOverrideFromWindowManager(
313            int displayId, DisplayInfo info) {
314        synchronized (mSyncRoot) {
315            LogicalDisplay display = mLogicalDisplays.get(displayId);
316            if (display != null) {
317                if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
318                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
319                    scheduleTraversalLocked(false);
320                }
321            }
322        }
323    }
324
325    /**
326     * Called by the window manager to perform traversals while holding a
327     * surface flinger transaction.
328     */
329    public void performTraversalInTransactionFromWindowManager() {
330        synchronized (mSyncRoot) {
331            if (!mPendingTraversal) {
332                return;
333            }
334            mPendingTraversal = false;
335
336            performTraversalInTransactionLocked();
337        }
338
339        // List is self-synchronized copy-on-write.
340        for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
341            listener.onDisplayTransaction();
342        }
343    }
344
345    /**
346     * Called by the power manager to blank all displays.
347     */
348    public void blankAllDisplaysFromPowerManager() {
349        synchronized (mSyncRoot) {
350            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
351                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
352                updateAllDisplayBlankingLocked();
353                scheduleTraversalLocked(false);
354            }
355        }
356    }
357
358    /**
359     * Called by the power manager to unblank all displays.
360     */
361    public void unblankAllDisplaysFromPowerManager() {
362        synchronized (mSyncRoot) {
363            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
364                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
365                updateAllDisplayBlankingLocked();
366                scheduleTraversalLocked(false);
367            }
368        }
369    }
370
371    /**
372     * Returns information about the specified logical display.
373     *
374     * @param displayId The logical display id.
375     * @return The logical display info, or null if the display does not exist.  The
376     * returned object must be treated as immutable.
377     */
378    @Override // Binder call
379    public DisplayInfo getDisplayInfo(int displayId) {
380        final int callingUid = Binder.getCallingUid();
381        final long token = Binder.clearCallingIdentity();
382        try {
383            synchronized (mSyncRoot) {
384                LogicalDisplay display = mLogicalDisplays.get(displayId);
385                if (display != null) {
386                    DisplayInfo info = display.getDisplayInfoLocked();
387                    if (info.hasAccess(callingUid)) {
388                        return info;
389                    }
390                }
391                return null;
392            }
393        } finally {
394            Binder.restoreCallingIdentity(token);
395        }
396    }
397
398    /**
399     * Returns the list of all display ids.
400     */
401    @Override // Binder call
402    public int[] getDisplayIds() {
403        final int callingUid = Binder.getCallingUid();
404        final long token = Binder.clearCallingIdentity();
405        try {
406            synchronized (mSyncRoot) {
407                final int count = mLogicalDisplays.size();
408                int[] displayIds = new int[count];
409                int n = 0;
410                for (int i = 0; i < count; i++) {
411                    LogicalDisplay display = mLogicalDisplays.valueAt(i);
412                    DisplayInfo info = display.getDisplayInfoLocked();
413                    if (info.hasAccess(callingUid)) {
414                        displayIds[n++] = mLogicalDisplays.keyAt(i);
415                    }
416                }
417                if (n != count) {
418                    displayIds = Arrays.copyOfRange(displayIds, 0, n);
419                }
420                return displayIds;
421            }
422        } finally {
423            Binder.restoreCallingIdentity(token);
424        }
425    }
426
427    @Override // Binder call
428    public void registerCallback(IDisplayManagerCallback callback) {
429        if (callback == null) {
430            throw new IllegalArgumentException("listener must not be null");
431        }
432
433        synchronized (mSyncRoot) {
434            int callingPid = Binder.getCallingPid();
435            if (mCallbacks.get(callingPid) != null) {
436                throw new SecurityException("The calling process has already "
437                        + "registered an IDisplayManagerCallback.");
438            }
439
440            CallbackRecord record = new CallbackRecord(callingPid, callback);
441            try {
442                IBinder binder = callback.asBinder();
443                binder.linkToDeath(record, 0);
444            } catch (RemoteException ex) {
445                // give up
446                throw new RuntimeException(ex);
447            }
448
449            mCallbacks.put(callingPid, record);
450        }
451    }
452
453    private void onCallbackDied(CallbackRecord record) {
454        synchronized (mSyncRoot) {
455            mCallbacks.remove(record.mPid);
456            stopWifiDisplayScanLocked(record);
457        }
458    }
459
460    @Override // Binder call
461    public void startWifiDisplayScan() {
462        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
463                "Permission required to start wifi display scans");
464
465        final int callingPid = Binder.getCallingPid();
466        final long token = Binder.clearCallingIdentity();
467        try {
468            synchronized (mSyncRoot) {
469                CallbackRecord record = mCallbacks.get(callingPid);
470                if (record == null) {
471                    throw new IllegalStateException("The calling process has not "
472                            + "registered an IDisplayManagerCallback.");
473                }
474                startWifiDisplayScanLocked(record);
475            }
476        } finally {
477            Binder.restoreCallingIdentity(token);
478        }
479    }
480
481    private void startWifiDisplayScanLocked(CallbackRecord record) {
482        if (!record.mWifiDisplayScanRequested) {
483            record.mWifiDisplayScanRequested = true;
484            if (mWifiDisplayScanRequestCount++ == 0) {
485                if (mWifiDisplayAdapter != null) {
486                    mWifiDisplayAdapter.requestStartScanLocked();
487                }
488            }
489        }
490    }
491
492    @Override // Binder call
493    public void stopWifiDisplayScan() {
494        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
495                "Permission required to stop wifi display scans");
496
497        final int callingPid = Binder.getCallingPid();
498        final long token = Binder.clearCallingIdentity();
499        try {
500            synchronized (mSyncRoot) {
501                CallbackRecord record = mCallbacks.get(callingPid);
502                if (record == null) {
503                    throw new IllegalStateException("The calling process has not "
504                            + "registered an IDisplayManagerCallback.");
505                }
506                stopWifiDisplayScanLocked(record);
507            }
508        } finally {
509            Binder.restoreCallingIdentity(token);
510        }
511    }
512
513    private void stopWifiDisplayScanLocked(CallbackRecord record) {
514        if (record.mWifiDisplayScanRequested) {
515            record.mWifiDisplayScanRequested = false;
516            if (--mWifiDisplayScanRequestCount == 0) {
517                if (mWifiDisplayAdapter != null) {
518                    mWifiDisplayAdapter.requestStopScanLocked();
519                }
520            } else if (mWifiDisplayScanRequestCount < 0) {
521                Log.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
522                        + mWifiDisplayScanRequestCount);
523                mWifiDisplayScanRequestCount = 0;
524            }
525        }
526    }
527
528    @Override // Binder call
529    public void connectWifiDisplay(String address) {
530        if (address == null) {
531            throw new IllegalArgumentException("address must not be null");
532        }
533        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
534                "Permission required to connect to a wifi display");
535
536        final long token = Binder.clearCallingIdentity();
537        try {
538            synchronized (mSyncRoot) {
539                if (mWifiDisplayAdapter != null) {
540                    mWifiDisplayAdapter.requestConnectLocked(address);
541                }
542            }
543        } finally {
544            Binder.restoreCallingIdentity(token);
545        }
546    }
547
548    @Override
549    public void pauseWifiDisplay() {
550        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
551                "Permission required to pause a wifi display session");
552
553        final long token = Binder.clearCallingIdentity();
554        try {
555            synchronized (mSyncRoot) {
556                if (mWifiDisplayAdapter != null) {
557                    mWifiDisplayAdapter.requestPauseLocked();
558                }
559            }
560        } finally {
561            Binder.restoreCallingIdentity(token);
562        }
563    }
564
565    @Override
566    public void resumeWifiDisplay() {
567        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
568                "Permission required to resume a wifi display session");
569
570        final long token = Binder.clearCallingIdentity();
571        try {
572            synchronized (mSyncRoot) {
573                if (mWifiDisplayAdapter != null) {
574                    mWifiDisplayAdapter.requestResumeLocked();
575                }
576            }
577        } finally {
578            Binder.restoreCallingIdentity(token);
579        }
580    }
581
582    @Override // Binder call
583    public void disconnectWifiDisplay() {
584        // This request does not require special permissions.
585        // Any app can request disconnection from the currently active wifi display.
586        // This exception should no longer be needed once wifi display control moves
587        // to the media router service.
588
589        final long token = Binder.clearCallingIdentity();
590        try {
591            synchronized (mSyncRoot) {
592                if (mWifiDisplayAdapter != null) {
593                    mWifiDisplayAdapter.requestDisconnectLocked();
594                }
595            }
596        } finally {
597            Binder.restoreCallingIdentity(token);
598        }
599    }
600
601    @Override // Binder call
602    public void renameWifiDisplay(String address, String alias) {
603        if (address == null) {
604            throw new IllegalArgumentException("address must not be null");
605        }
606        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
607                "Permission required to rename to a wifi display");
608
609        final long token = Binder.clearCallingIdentity();
610        try {
611            synchronized (mSyncRoot) {
612                if (mWifiDisplayAdapter != null) {
613                    mWifiDisplayAdapter.requestRenameLocked(address, alias);
614                }
615            }
616        } finally {
617            Binder.restoreCallingIdentity(token);
618        }
619    }
620
621    @Override // Binder call
622    public void forgetWifiDisplay(String address) {
623        if (address == null) {
624            throw new IllegalArgumentException("address must not be null");
625        }
626        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
627                "Permission required to forget to a wifi display");
628
629        final long token = Binder.clearCallingIdentity();
630        try {
631            synchronized (mSyncRoot) {
632                if (mWifiDisplayAdapter != null) {
633                    mWifiDisplayAdapter.requestForgetLocked(address);
634                }
635            }
636        } finally {
637            Binder.restoreCallingIdentity(token);
638        }
639    }
640
641    @Override // Binder call
642    public WifiDisplayStatus getWifiDisplayStatus() {
643        // This request does not require special permissions.
644        // Any app can get information about available wifi displays.
645
646        final long token = Binder.clearCallingIdentity();
647        try {
648            synchronized (mSyncRoot) {
649                if (mWifiDisplayAdapter != null) {
650                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
651                }
652                return new WifiDisplayStatus();
653            }
654        } finally {
655            Binder.restoreCallingIdentity(token);
656        }
657    }
658
659    @Override // Binder call
660    public int createVirtualDisplay(IBinder appToken, String packageName,
661            String name, int width, int height, int densityDpi, Surface surface, int flags) {
662        final int callingUid = Binder.getCallingUid();
663        if (!validatePackageName(callingUid, packageName)) {
664            throw new SecurityException("packageName must match the calling uid");
665        }
666        if (appToken == null) {
667            throw new IllegalArgumentException("appToken must not be null");
668        }
669        if (TextUtils.isEmpty(name)) {
670            throw new IllegalArgumentException("name must be non-null and non-empty");
671        }
672        if (width <= 0 || height <= 0 || densityDpi <= 0) {
673            throw new IllegalArgumentException("width, height, and densityDpi must be "
674                    + "greater than 0");
675        }
676        if (surface == null) {
677            throw new IllegalArgumentException("surface must not be null");
678        }
679        if (callingUid != Process.SYSTEM_UID &&
680                (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
681            if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
682                    != PackageManager.PERMISSION_GRANTED
683                    && mContext.checkCallingPermission(
684                            android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
685                            != PackageManager.PERMISSION_GRANTED) {
686                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
687                        + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
688                        + "public virtual display.");
689            }
690        }
691        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
692            if (mContext.checkCallingPermission(
693                    android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
694                    != PackageManager.PERMISSION_GRANTED) {
695                throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
696                        + "to create a secure virtual display.");
697            }
698        }
699
700        final long token = Binder.clearCallingIdentity();
701        try {
702            synchronized (mSyncRoot) {
703                if (mVirtualDisplayAdapter == null) {
704                    Slog.w(TAG, "Rejecting request to create private virtual display "
705                            + "because the virtual display adapter is not available.");
706                    return -1;
707                }
708
709                DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
710                        appToken, callingUid, packageName, name, width, height, densityDpi,
711                        surface, flags);
712                if (device == null) {
713                    return -1;
714                }
715
716                handleDisplayDeviceAddedLocked(device);
717                LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
718                if (display != null) {
719                    return display.getDisplayIdLocked();
720                }
721
722                // Something weird happened and the logical display was not created.
723                Slog.w(TAG, "Rejecting request to create virtual display "
724                        + "because the logical display was not created.");
725                mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
726                handleDisplayDeviceRemovedLocked(device);
727            }
728        } finally {
729            Binder.restoreCallingIdentity(token);
730        }
731        return -1;
732    }
733
734    @Override // Binder call
735    public void releaseVirtualDisplay(IBinder appToken) {
736        final long token = Binder.clearCallingIdentity();
737        try {
738            synchronized (mSyncRoot) {
739                if (mVirtualDisplayAdapter == null) {
740                    return;
741                }
742
743                DisplayDevice device =
744                        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
745                if (device != null) {
746                    handleDisplayDeviceRemovedLocked(device);
747                }
748            }
749        } finally {
750            Binder.restoreCallingIdentity(token);
751        }
752    }
753
754    private boolean validatePackageName(int uid, String packageName) {
755        if (packageName != null) {
756            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
757            if (packageNames != null) {
758                for (String n : packageNames) {
759                    if (n.equals(packageName)) {
760                        return true;
761                    }
762                }
763            }
764        }
765        return false;
766    }
767
768    private void registerDefaultDisplayAdapter() {
769        // Register default display adapter.
770        synchronized (mSyncRoot) {
771            registerDisplayAdapterLocked(new LocalDisplayAdapter(
772                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
773        }
774    }
775
776    private void registerAdditionalDisplayAdapters() {
777        synchronized (mSyncRoot) {
778            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
779                registerOverlayDisplayAdapterLocked();
780                registerWifiDisplayAdapterLocked();
781                registerVirtualDisplayAdapterLocked();
782            }
783        }
784    }
785
786    private void registerOverlayDisplayAdapterLocked() {
787        registerDisplayAdapterLocked(new OverlayDisplayAdapter(
788                mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
789    }
790
791    private void registerWifiDisplayAdapterLocked() {
792        if (mContext.getResources().getBoolean(
793                com.android.internal.R.bool.config_enableWifiDisplay)
794                || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
795            mWifiDisplayAdapter = new WifiDisplayAdapter(
796                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
797                    mPersistentDataStore);
798            registerDisplayAdapterLocked(mWifiDisplayAdapter);
799        }
800    }
801
802    private void registerVirtualDisplayAdapterLocked() {
803        mVirtualDisplayAdapter = new VirtualDisplayAdapter(
804                mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
805        registerDisplayAdapterLocked(mVirtualDisplayAdapter);
806    }
807
808    private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
809        // In safe mode, we disable non-essential display adapters to give the user
810        // an opportunity to fix broken settings or other problems that might affect
811        // system stability.
812        // In only-core mode, we disable non-essential display adapters to minimize
813        // the number of dependencies that are started while in this mode and to
814        // prevent problems that might occur due to the device being encrypted.
815        return !mSafeMode && !mOnlyCore;
816    }
817
818    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
819        mDisplayAdapters.add(adapter);
820        adapter.registerLocked();
821    }
822
823    private void handleDisplayDeviceAdded(DisplayDevice device) {
824        synchronized (mSyncRoot) {
825            handleDisplayDeviceAddedLocked(device);
826        }
827    }
828
829    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
830        if (mDisplayDevices.contains(device)) {
831            Slog.w(TAG, "Attempted to add already added display device: "
832                    + device.getDisplayDeviceInfoLocked());
833            return;
834        }
835
836        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
837
838        mDisplayDevices.add(device);
839        addLogicalDisplayLocked(device);
840        updateDisplayBlankingLocked(device);
841        scheduleTraversalLocked(false);
842    }
843
844    private void handleDisplayDeviceChanged(DisplayDevice device) {
845        synchronized (mSyncRoot) {
846            if (!mDisplayDevices.contains(device)) {
847                Slog.w(TAG, "Attempted to change non-existent display device: "
848                        + device.getDisplayDeviceInfoLocked());
849                return;
850            }
851
852            Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
853
854            device.applyPendingDisplayDeviceInfoChangesLocked();
855            if (updateLogicalDisplaysLocked()) {
856                scheduleTraversalLocked(false);
857            }
858        }
859    }
860
861    private void handleDisplayDeviceRemoved(DisplayDevice device) {
862        synchronized (mSyncRoot) {
863            handleDisplayDeviceRemovedLocked(device);
864        }
865    }
866    private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
867        if (!mDisplayDevices.remove(device)) {
868            Slog.w(TAG, "Attempted to remove non-existent display device: "
869                    + device.getDisplayDeviceInfoLocked());
870            return;
871        }
872
873        Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
874
875        updateLogicalDisplaysLocked();
876        scheduleTraversalLocked(false);
877    }
878
879    private void updateAllDisplayBlankingLocked() {
880        final int count = mDisplayDevices.size();
881        for (int i = 0; i < count; i++) {
882            DisplayDevice device = mDisplayDevices.get(i);
883            updateDisplayBlankingLocked(device);
884        }
885    }
886
887    private void updateDisplayBlankingLocked(DisplayDevice device) {
888        // Blank or unblank the display immediately to match the state requested
889        // by the power manager (if known).
890        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
891        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
892            switch (mAllDisplayBlankStateFromPowerManager) {
893                case DISPLAY_BLANK_STATE_BLANKED:
894                    device.blankLocked();
895                    break;
896                case DISPLAY_BLANK_STATE_UNBLANKED:
897                    device.unblankLocked();
898                    break;
899            }
900        }
901    }
902
903    // Adds a new logical display based on the given display device.
904    // Sends notifications if needed.
905    private void addLogicalDisplayLocked(DisplayDevice device) {
906        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
907        boolean isDefault = (deviceInfo.flags
908                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
909        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
910            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
911            isDefault = false;
912        }
913
914        if (!isDefault && mSingleDisplayDemoMode) {
915            Slog.i(TAG, "Not creating a logical display for a secondary display "
916                    + " because single display demo mode is enabled: " + deviceInfo);
917            return;
918        }
919
920        final int displayId = assignDisplayIdLocked(isDefault);
921        final int layerStack = assignLayerStackLocked(displayId);
922
923        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
924        display.updateLocked(mDisplayDevices);
925        if (!display.isValidLocked()) {
926            // This should never happen currently.
927            Slog.w(TAG, "Ignoring display device because the logical display "
928                    + "created from it was not considered valid: " + deviceInfo);
929            return;
930        }
931
932        mLogicalDisplays.put(displayId, display);
933
934        // Wake up waitForDefaultDisplay.
935        if (isDefault) {
936            mSyncRoot.notifyAll();
937        }
938
939        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
940    }
941
942    private int assignDisplayIdLocked(boolean isDefault) {
943        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
944    }
945
946    private int assignLayerStackLocked(int displayId) {
947        // Currently layer stacks and display ids are the same.
948        // This need not be the case.
949        return displayId;
950    }
951
952    // Updates all existing logical displays given the current set of display devices.
953    // Removes invalid logical displays.
954    // Sends notifications if needed.
955    private boolean updateLogicalDisplaysLocked() {
956        boolean changed = false;
957        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
958            final int displayId = mLogicalDisplays.keyAt(i);
959            LogicalDisplay display = mLogicalDisplays.valueAt(i);
960
961            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
962            display.updateLocked(mDisplayDevices);
963            if (!display.isValidLocked()) {
964                mLogicalDisplays.removeAt(i);
965                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
966                changed = true;
967            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
968                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
969                changed = true;
970            }
971        }
972        return changed;
973    }
974
975    private void performTraversalInTransactionLocked() {
976        // Clear all viewports before configuring displays so that we can keep
977        // track of which ones we have configured.
978        clearViewportsLocked();
979
980        // Configure each display device.
981        final int count = mDisplayDevices.size();
982        for (int i = 0; i < count; i++) {
983            DisplayDevice device = mDisplayDevices.get(i);
984            configureDisplayInTransactionLocked(device);
985            device.performTraversalInTransactionLocked();
986        }
987
988        // Tell the input system about these new viewports.
989        if (mInputManagerFuncs != null) {
990            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
991        }
992    }
993
994    /**
995     * Tells the display manager whether there is interesting unique content on the
996     * specified logical display.  This is used to control automatic mirroring.
997     * <p>
998     * If the display has unique content, then the display manager arranges for it
999     * to be presented on a physical display if appropriate.  Otherwise, the display manager
1000     * may choose to make the physical display mirror some other logical display.
1001     * </p>
1002     *
1003     * @param displayId The logical display id to update.
1004     * @param hasContent True if the logical display has content.
1005     * @param inTraversal True if called from WindowManagerService during a window traversal prior
1006     * to call to performTraversalInTransactionFromWindowManager.
1007     */
1008    public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) {
1009        synchronized (mSyncRoot) {
1010            LogicalDisplay display = mLogicalDisplays.get(displayId);
1011            if (display != null && display.hasContentLocked() != hasContent) {
1012                if (DEBUG) {
1013                    Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
1014                            + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
1015                }
1016
1017                display.setHasContentLocked(hasContent);
1018                scheduleTraversalLocked(inTraversal);
1019            }
1020        }
1021    }
1022
1023    private void clearViewportsLocked() {
1024        mDefaultViewport.valid = false;
1025        mExternalTouchViewport.valid = false;
1026    }
1027
1028    private void configureDisplayInTransactionLocked(DisplayDevice device) {
1029        final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
1030        final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
1031
1032        // Find the logical display that the display device is showing.
1033        // Certain displays only ever show their own content.
1034        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
1035        if (!ownContent) {
1036            if (display != null && !display.hasContentLocked()) {
1037                // If the display does not have any content of its own, then
1038                // automatically mirror the default logical display contents.
1039                display = null;
1040            }
1041            if (display == null) {
1042                display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
1043            }
1044        }
1045
1046        // Apply the logical display configuration to the display device.
1047        if (display == null) {
1048            // TODO: no logical display for the device, blank it
1049            Slog.w(TAG, "Missing logical display to use for physical display device: "
1050                    + device.getDisplayDeviceInfoLocked());
1051            return;
1052        }
1053        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
1054                && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
1055        display.configureDisplayInTransactionLocked(device, isBlanked);
1056
1057        // Update the viewports if needed.
1058        if (!mDefaultViewport.valid
1059                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
1060            setViewportLocked(mDefaultViewport, display, device);
1061        }
1062        if (!mExternalTouchViewport.valid
1063                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
1064            setViewportLocked(mExternalTouchViewport, display, device);
1065        }
1066    }
1067
1068    private static void setViewportLocked(DisplayViewport viewport,
1069            LogicalDisplay display, DisplayDevice device) {
1070        viewport.valid = true;
1071        viewport.displayId = display.getDisplayIdLocked();
1072        device.populateViewportLocked(viewport);
1073    }
1074
1075    private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
1076        final int count = mLogicalDisplays.size();
1077        for (int i = 0; i < count; i++) {
1078            LogicalDisplay display = mLogicalDisplays.valueAt(i);
1079            if (display.getPrimaryDisplayDeviceLocked() == device) {
1080                return display;
1081            }
1082        }
1083        return null;
1084    }
1085
1086    private void sendDisplayEventLocked(int displayId, int event) {
1087        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
1088        mHandler.sendMessage(msg);
1089    }
1090
1091    // Requests that performTraversalsInTransactionFromWindowManager be called at a
1092    // later time to apply changes to surfaces and displays.
1093    private void scheduleTraversalLocked(boolean inTraversal) {
1094        if (!mPendingTraversal && mWindowManagerFuncs != null) {
1095            mPendingTraversal = true;
1096            if (!inTraversal) {
1097                mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
1098            }
1099        }
1100    }
1101
1102    // Runs on Handler thread.
1103    // Delivers display event notifications to callbacks.
1104    private void deliverDisplayEvent(int displayId, int event) {
1105        if (DEBUG) {
1106            Slog.d(TAG, "Delivering display event: displayId="
1107                    + displayId + ", event=" + event);
1108        }
1109
1110        // Grab the lock and copy the callbacks.
1111        final int count;
1112        synchronized (mSyncRoot) {
1113            count = mCallbacks.size();
1114            mTempCallbacks.clear();
1115            for (int i = 0; i < count; i++) {
1116                mTempCallbacks.add(mCallbacks.valueAt(i));
1117            }
1118        }
1119
1120        // After releasing the lock, send the notifications out.
1121        for (int i = 0; i < count; i++) {
1122            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
1123        }
1124        mTempCallbacks.clear();
1125    }
1126
1127    @Override // Binder call
1128    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1129        if (mContext == null
1130                || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
1131                        != PackageManager.PERMISSION_GRANTED) {
1132            pw.println("Permission Denial: can't dump DisplayManager from from pid="
1133                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1134            return;
1135        }
1136
1137        pw.println("DISPLAY MANAGER (dumpsys display)");
1138
1139        synchronized (mSyncRoot) {
1140            pw.println("  mOnlyCode=" + mOnlyCore);
1141            pw.println("  mSafeMode=" + mSafeMode);
1142            pw.println("  mPendingTraversal=" + mPendingTraversal);
1143            pw.println("  mAllDisplayBlankStateFromPowerManager="
1144                    + mAllDisplayBlankStateFromPowerManager);
1145            pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
1146            pw.println("  mDefaultViewport=" + mDefaultViewport);
1147            pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
1148            pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
1149            pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
1150
1151            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
1152            ipw.increaseIndent();
1153
1154            pw.println();
1155            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
1156            for (DisplayAdapter adapter : mDisplayAdapters) {
1157                pw.println("  " + adapter.getName());
1158                adapter.dumpLocked(ipw);
1159            }
1160
1161            pw.println();
1162            pw.println("Display Devices: size=" + mDisplayDevices.size());
1163            for (DisplayDevice device : mDisplayDevices) {
1164                pw.println("  " + device.getDisplayDeviceInfoLocked());
1165                device.dumpLocked(ipw);
1166            }
1167
1168            final int logicalDisplayCount = mLogicalDisplays.size();
1169            pw.println();
1170            pw.println("Logical Displays: size=" + logicalDisplayCount);
1171            for (int i = 0; i < logicalDisplayCount; i++) {
1172                int displayId = mLogicalDisplays.keyAt(i);
1173                LogicalDisplay display = mLogicalDisplays.valueAt(i);
1174                pw.println("  Display " + displayId + ":");
1175                display.dumpLocked(ipw);
1176            }
1177
1178            final int callbackCount = mCallbacks.size();
1179            pw.println();
1180            pw.println("Callbacks: size=" + callbackCount);
1181            for (int i = 0; i < callbackCount; i++) {
1182                CallbackRecord callback = mCallbacks.valueAt(i);
1183                pw.println("  " + i + ": mPid=" + callback.mPid
1184                        + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
1185            }
1186        }
1187    }
1188
1189    /**
1190     * This is the object that everything in the display manager locks on.
1191     * We make it an inner class within the {@link DisplayManagerService} to so that it is
1192     * clear that the object belongs to the display manager service and that it is
1193     * a unique object with a special purpose.
1194     */
1195    public static final class SyncRoot {
1196    }
1197
1198    /**
1199     * Private interface to the window manager.
1200     */
1201    public interface WindowManagerFuncs {
1202        /**
1203         * Request that the window manager call
1204         * {@link #performTraversalInTransactionFromWindowManager} within a surface
1205         * transaction at a later time.
1206         */
1207        void requestTraversal();
1208    }
1209
1210    /**
1211     * Private interface to the input manager.
1212     */
1213    public interface InputManagerFuncs {
1214        /**
1215         * Sets information about the displays as needed by the input system.
1216         * The input system should copy this information if required.
1217         */
1218        void setDisplayViewports(DisplayViewport defaultViewport,
1219                DisplayViewport externalTouchViewport);
1220    }
1221
1222    private final class DisplayManagerHandler extends Handler {
1223        public DisplayManagerHandler(Looper looper) {
1224            super(looper, null, true /*async*/);
1225        }
1226
1227        @Override
1228        public void handleMessage(Message msg) {
1229            switch (msg.what) {
1230                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
1231                    registerDefaultDisplayAdapter();
1232                    break;
1233
1234                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
1235                    registerAdditionalDisplayAdapters();
1236                    break;
1237
1238                case MSG_DELIVER_DISPLAY_EVENT:
1239                    deliverDisplayEvent(msg.arg1, msg.arg2);
1240                    break;
1241
1242                case MSG_REQUEST_TRAVERSAL:
1243                    mWindowManagerFuncs.requestTraversal();
1244                    break;
1245
1246                case MSG_UPDATE_VIEWPORT: {
1247                    synchronized (mSyncRoot) {
1248                        mTempDefaultViewport.copyFrom(mDefaultViewport);
1249                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
1250                    }
1251                    mInputManagerFuncs.setDisplayViewports(
1252                            mTempDefaultViewport, mTempExternalTouchViewport);
1253                    break;
1254                }
1255            }
1256        }
1257    }
1258
1259    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
1260        @Override
1261        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
1262            switch (event) {
1263                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
1264                    handleDisplayDeviceAdded(device);
1265                    break;
1266
1267                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
1268                    handleDisplayDeviceChanged(device);
1269                    break;
1270
1271                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
1272                    handleDisplayDeviceRemoved(device);
1273                    break;
1274            }
1275        }
1276
1277        @Override
1278        public void onTraversalRequested() {
1279            synchronized (mSyncRoot) {
1280                scheduleTraversalLocked(false);
1281            }
1282        }
1283    }
1284
1285    private final class CallbackRecord implements DeathRecipient {
1286        public final int mPid;
1287        private final IDisplayManagerCallback mCallback;
1288
1289        public boolean mWifiDisplayScanRequested;
1290
1291        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
1292            mPid = pid;
1293            mCallback = callback;
1294        }
1295
1296        @Override
1297        public void binderDied() {
1298            if (DEBUG) {
1299                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
1300            }
1301            onCallbackDied(this);
1302        }
1303
1304        public void notifyDisplayEventAsync(int displayId, int event) {
1305            try {
1306                mCallback.onDisplayEvent(displayId, event);
1307            } catch (RemoteException ex) {
1308                Slog.w(TAG, "Failed to notify process "
1309                        + mPid + " that displays changed, assuming it died.", ex);
1310                binderDied();
1311            }
1312        }
1313    }
1314}
1315