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