Commit Graph

421 Commits

Author SHA1 Message Date
Pavel Maltsev
4f2be07902 Merge "Check black-listed USB class before descriptor" 2018-09-14 04:58:25 +00:00
TreeHugger Robot
1a56d75fb4 Merge "USB permission and resolve activity refactor." 2018-09-05 20:05:50 +00:00
Paul Mclean
2e656695b3 Merge "Make single-USB-peripheral only mode a compile-time option." 2018-09-05 19:46:35 +00:00
Paul McLean
519c557eca Make single-USB-peripheral only mode a compile-time option.
Allow multi-usb work to continue without changes spinning out of control.

Bug: 111397675
Test: Set single-mode on and verify correct behavior.

Change-Id: I70f70bbb8edae6cbd1e73bee40fe821079cba9d8
2018-09-04 08:19:42 -06:00
lgcheng
2992e1c716 USB permission and resolve activity refactor.
Pure refactor of USB code for simple Arc logic injection.
Should have no behavior change for AOSP.

Bug: 74258201
Test: Run USB Accessory and USB Device test.
Change-Id: I8f7dace9155ceb75bc465fbb03a26f52694c8f93
2018-08-30 21:39:59 +00:00
Philip P. Moltmann
cf4ea753de Merge "UsbDeviceManager: Check PTP FileDescriptor properly" am: a0a67862aa am: 353543639f
am: 8ccef1b9f3

Change-Id: I70df6ac9cf0c39d4c59bbe79c18388dbe23419c2
2018-08-30 12:57:33 -07:00
Wang Han
e030a09023 UsbDeviceManager: Check PTP FileDescriptor properly
* A typo causes MTP one to be checked twice

Change-Id: If16bf5df43b6d51f6717aa7994b2f428fb3f1a69
2018-08-30 06:28:36 +00:00
Pavel Maltsev
e8c3a3e92c Check black-listed USB class before descriptor
Attempt to read USB descriptor of USB hub devices results in hanging
thread on getDescriptorString_native call.  Also check device
interface class/subclass as well.

Test: verified that usb host thread no longer stuch in getDescriptorString_native call on Mojave board with USB hub attached

Bug: 112657091

Change-Id: I46271dcc9c80168a650940fbde9218a54cafe8da
2018-08-16 13:59:40 -07:00
Jerry Zhang
626a5c69c7 Merge "UsbDescriptor: Add finite timeout to control transfer" am: 20dca26f41 am: 4bff76be80
am: db3a291e9d

Change-Id: Ibf2bc0673e156919baf77c0db2033aa521b08052
2018-07-17 15:09:35 -07:00
Jerry Zhang
4bff76be80 Merge "UsbDescriptor: Add finite timeout to control transfer"
am: 20dca26f41

Change-Id: I86a916694a497bedb7d2df8a64dd17e0e15ce332
2018-07-17 13:59:15 -07:00
sgopal1
58484d7c69 UsbDescriptor: Add finite timeout to control transfer
Using "0" as value for USB control transfer timeout
results in an unlimited timeout in case of bad USB
devices. In host kernels where hung task panic
is enabled, this results in device reboot.
So, add a finite timeout for USB control transfer.

Test: manual run and test with bad USB devices.

Change-Id: Ibc13ca4d8259a08ae7419bb3bcac9c161b1d3693
Signed-off-by: sgopal1 <saranya.gopal@intel.com>
2018-07-10 09:54:03 +05:30
Wale Ogunwale
9e4f3e077f Introduced WindowProcessController/Listener (10/n)
One heavy dependence between the current AMS service and activities
is process management which is heavy affected by activities and their
current state. We introduce WindowProcessController and WindowProcessListener
objects as a structured way for the process changes in AM package to
be communicated to the WM package and WindowProcessListner for activity
changes in the WM package to the communicated back to the AM package.
The ProcessRecord object in AM will own the WindowProcessController object
and also implement the WindowProcessListener.

Test: Existing tests pass
Test: go/wm-smoke-auto
Bug: 80414790
Change-Id: I9e96e841b0f95e99a597cb4629fa5d2fe45760b6
2018-06-22 14:26:24 -07:00
Wale Ogunwale
6767eaee94 Split internal interface activities from current AM interface (3/n)
3rd step in unifying the window hierarchy that is currently split
within AM and WM packages. We separate the the internal interface used
to communicate within system server dealing with activities and their
containers (tasks, stack, display) from the rest of AM internal
interface.

Test: Existing tests pass
Test: go/wm-smoke-auto
Bug: 80414790
Change-Id: Idad77721c1fe10621b9be5dced42a0a11f0183e5
2018-06-15 08:43:22 -07:00
Philip P. Moltmann
66c5a8d207 Dump activities that handle when USB devices get plugged in
When a USB device or accessory gets plugged in the system might
automatically start activities that have a device/accessory filter set
to include the plugged in USB device.

Unfortunately we seen too many apps setting too broad of a filter and it
annoys the user that this apps wants to start every time the device gets
plugged in.

This change dumps the acitivity names and their filters so debugging
such issues is much easier.

To do this, there is some mild refactoring:

1. Split packageMatchesLocked into
- getDeviceFilters to resolve all device filters
- getAccessoryFilterer to resolve all accessories
- Check if a filter matches after resolving all filters. This is no
  performance issue as usually there is only one or two filters per
  activity.

2. Split queryIntentActivitiesForAllProfiles into
- A per user part, so that we can use the exact same intent-resolution
  code for the dump-code
- And a loop over the per user part

Test: adb shell dumpsys usb
      + incident_report usb
      + verified that the output is as expected

Change-Id: I552c963b9a1b1c7df0adc6746af8cd42a4691cd6
2018-05-31 11:12:32 -07:00
Kweku Adams
3984cf625c Fixing typo in proto field.
Bug: 72814439
Bug: 74975371
Test: atest CtsIncidentHostTestCases:com.android.server.cts.UsbIncidentTest
Change-Id: Ia04c13b96bd1996e6e96f9b4e2e693af4cb97070
2018-04-11 16:35:50 -07:00
Jerry Zhang
df101a4596 Merge "Write descriptors for Mtp in UsbService" into pi-dev 2018-03-27 02:49:02 +00:00
Andrew Chant
608ec66d62 UsbHostManager: Restore inserted device logging
Restore logcat logging of newly-added USB devices.
Eliminate blacklist log lines.

Test: Connected USB Storage and USB audio devices.
Updated UsbDescriptorParserTests for device descriptor
version.

example output:
UsbHostManager: USB device attached: vidpid 03eb:2433 mfg/product/ver/serial Libratone/Libratone_INEAR/1.00/Inear_mcu_app_0.2.1_20160304 hasAudio/HID/Storage: true/true/false
UsbHostManager: USB device attached: vidpid 05dc:a82b mfg/product/ver/serial Lexar/ARA Storage /2.08/0024070163400215 hasAudio/HID/Storage: false/false/true
UsbHostManager: USB device attached: vidpid 18d1:5029 mfg/product/ver/serial Google/USB-C to 3.5mm-Headphone Adapter/22.80/201405280001 hasAudio/HID/Storage: false/true/false
UsbHostManager: USB device attached: vidpid 18d1:5025 mfg/product/ver/serial Google/USB-C to 3.5mm-Headphone Adapter/22.80/201405280001 hasAudio/HID/Storage: true/true/false

Bug: 74119682
Change-Id: I72688f651c819d4bdc48f6d6316570ca5fc54d1e
2018-03-26 20:55:54 +00:00
Andrew Chant
0491f5aa0f UsbDescriptorParser: always parse in constructor
UsbDescriptorParser::parseDescriptors always returned true.
Remove the return value, and remove the one constructor that
doesn't parse descriptors so the device is always in a parsed state.

Bug: 74119682
Test: Built
Change-Id: I2dd8d439405867d78102a9591dd1db36fe3959dc
2018-03-26 20:55:28 +00:00
Jerry Zhang
6d319b8aaa Write descriptors for Mtp in UsbService
The current model for setting up a functionfs
function is:

UsbDeviceManager#setCurrentFunctions() ->
intent is sent to MtpReceiver to write the descriptors ->
init/hal waits for descriptors to write, then pulls up gadget ->
Gadget is configured, a USB_STATE intent starts MtpServer

The main downside of this is a lack of reliability because
the Mtp process could be killed at any point. Normally, a
gadget is unbound if its control endpoint is closed. no_disconnect
works around this, but is still a little janky. In addition, the
extra intent delays the startup of the gadget.

With the new model, UsbDeviceManager writes the descriptors
on initialization. Since it is a system service, it won't be killed.

UsbDeviceManager#setCurrentFunctions() ->
init/hal pulls up gadget ->
Gadget is configured, a USB_STATE intent starts MtpServer
MtpServer calls UsbManager#getControlFd to get a dup of the control
endpoint.

Also modify permissions so system server can access mtp files.

Bug: 72877174
Test: Change usb configurations to ptp/mtp
Change-Id: Id17d2b5930f4e1f37ec1b4f00add9d594174ad49
2018-03-22 11:35:19 -07:00
TreeHugger Robot
ff1f7090c6 Merge "Set systemReady before querying the portStatus." 2018-02-28 02:52:31 +00:00
TreeHugger Robot
23aee1bbb5 Merge changes from topic "terminal_type_fix"
* changes:
  Add test for UsbDescriptorParser.java
  USB Audio: broaden Terminal Type interpretation
2018-02-28 00:09:15 +00:00
Badhri Jagan Sridharan
d399f2eaff Set systemReady before querying the portStatus.
Since the callbacks are async, its possible that the callback gets
called before the systemReady flag is set.

Change-Id: I5752c097e25ef30a151461540dd7d5323cc927af
2018-02-27 22:56:45 +00:00
Andrew Chant
0ef73801f5 USB Audio: broaden Terminal Type interpretation
Terminal type is currently used to determine presence of audio input
or output capabilities on audio devices.

Broaden the set of terminal types accepted as inputs and outputs.

Test: Verified by playing with USB-C to 3.5mm adapter with
high impedance load, checked Terminal type reported as 0x0603.
Verified no audio on old build, audio on new build.
Checked with low impedance load with and without microphone.
Checked with no load.

Bug: 73813676
Change-Id: Ib9b291e4770dc3c03157df7ac4277da1692174d7
2018-02-26 14:39:46 -08:00
Jerry Zhang
20b1414fe0 Initialize functions as NONE in legacy handler.
Since adb is being removed from the functions read
from sys.usb.config anyway, it makes more sense to
set it to NONE on boot. This prevents errors with
devices that already have oem functions in the config.

Bug: 73010922
Test: Power test passes
Change-Id: I855ba228dbdd9f8c8a91842a8beb68a789fdf1e9
2018-02-24 02:19:16 +00:00
Andrew Chant
5f53db38b2 Merge changes from topic "uac_jackdetect"
* changes:
  Add a selected UsbAlsaDevice
  ALSA jack detection support
  Synchronize UsbAlsaDevice, rename playback/capture.
2018-02-14 19:00:23 +00:00
Andrew Chant
278f4c9a05 Add a selected UsbAlsaDevice
Keep track of the currently selected UsbAlsaDevice in a
synchronized manner.
Allow it to notify AudioService that it has been disabled
prior to replacing it with a new Audio Device.

Test: verified audio worked as expected when using
both UAC2 and non-UAC2 3.5mm adapters, with 3.5mm
plugging/unplugging and USB-C plugging/unplugging.

Change-Id: I8b76145490da38d4eec25f4f2bdb6695afa151b9
2018-02-13 16:51:34 -08:00
Andrew Chant
07a97da51f ALSA jack detection support
Adds support for ALSA jack detection for USB.
Spawns a new thread for ALSA jack detection on device
insert.  If the device doesn't support ALSA jack detection,
the thread terminates.

Test: UAC2 audio accessory and a kernel
which supports USB ALSA Jack detection, switching between
speaker and USB works perfectly with plug/unplug at jack.

Bug: 68337205
Bug: 70632415
Change-Id: I1800660ad4d2341f19ce7be6d6b01f81a7f2d1a6
2018-02-13 16:42:35 -08:00
Jerry Zhang
2135f41477 Don't set functions at registration on boot
If onRegistration is called before functions
are received, adb can be kicked on boot. To fix,
don't set functions if they are still being
requested.

Bug: 73168456
Test: adb logcat doesn't dc
Change-Id: I25bfe13604f0ce0c65c3eb82bcfafd9fcae0283f
2018-02-13 12:58:41 -08:00
Andrew Chant
54b15e98cd Synchronize UsbAlsaDevice, rename playback/capture.
Synchronize external access to UsbAlsaDevice fields.
Rename all playback fields to output, capture to input.
Move Alsa Device String generation to UsbAlsaDevice.

Test: Used Google Play Music to test audio output while
inserting & removing USB audio devices.

Bug: 68337205
Bug: 70632415
Change-Id: I77d413736253e28a33993f45e6e405209563f3e4
2018-02-12 15:45:48 -08:00
Andreas Gampe
bbab23ff97 Frameworks: Annotate trivial @GuardedBy in services/ misc
Add @GuardedBy for simple functions that require a single lock
and are named XYZLocked.

Derived by errorprone.

Bug: 73000847
Test: m
Test: m javac-check-framework RUN_ERROR_PRONE=true
Change-Id: Id1d9fbe5018250e3b9d1466fc5f670d5ad902fa3
2018-02-08 02:19:42 -08:00
Jerry Zhang
d33a85c4d7 Merge "Move sharedPreferences to DE directory" 2018-02-05 19:25:34 +00:00
Philip P. Moltmann
371a3b879b Dump usb as DualDump
This allows to dump the USB state as proto-buf. This in turn allows to
automatically process this data.

Test: adb shell dumpsys usb
      incident_report usb
      No automated test possible as no field is guaranteed to be set
Change-Id: Ifdf22bfaf9c78226c420b11c43278013ce69f849
2018-02-02 16:40:26 -08:00
Jerry Zhang
0be310a303 Move sharedPreferences to DE directory
Prevents crashes / loss of behavior when
user 0 is locked, but another user is
unlocked.

Bug: 72662661
Test: have lock on user 0, reboot, switch to and unlock user 10
Change-Id: I72767fc4726d3b316266a1499dbe51bd7d9830bc
2018-02-02 12:49:47 -08:00
Paul McLean
16d7913d98 Optimize/streamline USB audio (dis)connect
Map from usb device "address" to ALSA card num.
Remove Alsa filespace monitor.

Bug: 72435641

Test: Connect various devices and check for correct input/out determination.
Prototype Headset, Presonus AudioBox 22VSL...

Change-Id: I9e25b3e9c1c3280c26171873c0a48c58cbb99fb5
2018-02-02 09:38:38 -07:00
Paul McLean
50c00924d8 renamed UsbAudioDevice.java to UsbAlsaDevice.java
Test: Manual, build, run... AOK.

Change-Id: Iba43f94fd74aad826891534c648e61db0d0423b2
2018-02-02 09:31:50 -07:00
Jerry Zhang
e649748eb6 Parse persist property the legacy way
Devices like bat still have oem functions
in the persist prop, so don't throw errors.

Test: device boots
Bug: 72765363
Change-Id: I7d1e334d7cafb1ba1f328ee4160da3b098f76fa1
2018-02-01 02:21:07 +00:00
Jerry Zhang
28b6fc9c25 Usb changes and strings for connected devices 2.0
New metrics constant and usb strings for the new
notification / details page.

Bug: 69333961
Test: Check notification
Change-Id: If9bde7f787e40e42bb991a99b032e1ff968a0a41
2018-01-31 11:40:53 -08:00
Jerry Zhang
327b809ad1 Refactor and clean up USB, add tests
Change UsbManager apis to use long instead of string, to match
usb hal. Change UsbDeviceManager internals to match as well.

Remove isFunctionEnabled and add getEnabledFunctions. Callers
would often call isFunctionEnabled for every possible function
to get the list of functions, so getEnabledFunctions reduces the
number of aidl calls.

Separate out dependencies between UsbHandler and UsbDeviceManager
and staticize the UsbHandler classes. Add unit tests with
mocked out dependencies to test state transitions for UsbHandler.

Bug: 62876645
Test: atest UsbTests
Change-Id: I785c4c24121a70e725de9742c6af50a6bf1baea0
2018-01-31 11:40:48 -08:00
Dianne Hackborn
e17b445b6c Reduce pss collection amount, improve logging.
Tuned rates that we collect PSS, to reduce how much we do
that heavy operation.  Added a new way to determine
whether a process has changed to a state for the
"first" time -- now this is when it has gone to that
state for the first time since it was in a lower state.
This will reduce the amount of time we consider a
process to be first to only when it has previously
gone into a higher state than it had before.

Keep track of more fine-grained information about why we
collect a PSS sample (not just internal, but for a single
process, all processes because of a mem state change, all
processes because of a poll).

Started collecting RSS in various places, so we can start
looking at that w.r.t. PSS and see about transitioning to
it is a new primary metric.

Added logging for many of the places where the system
writes its configuration files, so we can more easily
see any bad behavior going on in those areas.

Added some currently disabled code to read smaps directly
instead of using fgets().  Probably won't help, but want
tot test.

Bug: 70859548
Test: atest CtsAppTestCases
Change-Id: I400dba0f3ae9c024df51c946cfa592561028b598
2018-01-26 15:15:04 -08:00
Badhri Jagan Sridharan
6754ca81c2 Add support for UsbDeviceManager to talk to USB GADGET HAL
Till now, Init scripts(property tiggers) are used define the
operation that needs to be performed when a certain gadget
composition needs to be enabled. Based on the user preference,
usb service sets the sys.usb.config which triggers the
corresponding property triggers in init scripts and usbservice
polls on sys.usb.state to infer whether the property triggers
have completed executing.

This CL makes UsbHandler class abstract to make init scripts
based legacy implementation and HAL based implementation to
share the common logic. The legacy init script based logic is
implemented by UsbHandlerLegacy and HAL based logic is implemented
by UsbHandlerHal. The decision on which one to initialize is
made depending on whether the device has Gadget HAL impelemented.

Since HIDL supports asynch calbacks, usb state management is moved
to the message queue to avoid polling incase of HAL based
implementation.

To switch to a new configuration:
1. UsbService calls setCurrentUsbFunctions and queues
   MSG_SET_FUNCTIONS_TIMEOUT
2. If the  setCurrentUsbFunctionsCb arrives on time,
   then  MSG_SET_FUNCTIONS_TIMEOUT is cancelled and
   default functions are retried by queueing
   MSG_SET_DEFAULT_FUNCTIONS if SUCCESS is not signalled.
3. If MSG_SET_FUNCTIONS_TIMEOUT gets executed, then,
   default functions are retried by calling
   setEnabledFunctions(null, false, mUsbDataUnlocked);

Also, for HAL based implementation config_oemUsbModeOverride is no
longer needed as hal can take of enabling oem specific functions.

Bug: 63669128
Test: Tested usb gadget configuration for both cases:
1. When gadget hal is present
2. When gadget hal is not present
Change-Id: Ifcef464a0b97b265872696346a76162f8e84d6c0
2018-01-25 14:42:42 +00:00
Badhri Jagan Sridharan
5eb97dcf50 Add support for UsbDeviceManager to talk to USB GADGET HAL
Till now, Init scripts(property tiggers) are used define the
operation that needs to be performed when a certain gadget
composition needs to be enabled. Based on the user preference,
usb service sets the sys.usb.config which triggers the
corresponding property triggers in init scripts and usbservice
polls on sys.usb.state to infer whether the property triggers
have completed executing.

This CL makes UsbHandler class abstract to make init scripts
based legacy implementation and HAL based implementation to
share the common logic. The legacy init script based logic is
implemented by UsbHandlerLegacy and HAL based logic is implemented
by UsbHandlerHal. The decision on which one to initialize is
made depending on whether the device has Gadget HAL impelemented.

Since HIDL supports asynch calbacks, usb state management is moved
to the message queue to avoid polling incase of HAL based
implementation.

To switch to a new configuration:
1. UsbService calls setCurrentUsbFunctions and queues
   MSG_SET_FUNCTIONS_TIMEOUT
2. If the  setCurrentUsbFunctionsCb arrives on time,
   then  MSG_SET_FUNCTIONS_TIMEOUT is cancelled and
   default functions are retried by queueing
   MSG_SET_DEFAULT_FUNCTIONS if SUCCESS is not signalled.
3. If MSG_SET_FUNCTIONS_TIMEOUT gets executed, then,
   default functions are retried by calling
   setEnabledFunctions(null, false, mUsbDataUnlocked);

Also, for HAL based implementation config_oemUsbModeOverride is no
longer needed as hal can take of enabling oem specific functions.

Bug: 63669128
Test: Tested usb gadget configuration for both cases:
1. When gadget hal is present
2. When gadget hal is not present
Change-Id: Ifcef464a0b97b265872696346a76162f8e84d6c0
2018-01-22 17:02:25 -08:00
Jerry Zhang
7ca5d3a334 DO NOT MERGE: Add setScreenUnlockedFunctions method to UsbManager
Cherry-pick from 30b9adfad1

The screen unlocked functions save effort on setting
the usb config during each connection. These
functions persist between connections and between
boots. When the screen is unlocked and these
functions are set, the current functions will
be automatically set to the screen unlocked functions.

Also added svc command for this so it can be
used and tested while the UI is worked on.

Bug: 62876645
Test: svc usb setScreenUnlockedFunctions mtp
Test: Test functions with locking, unlocking, and
disconnecting, with no lockscreen, swipe, and pattern

Change-Id: Ia05e095917166d25398c4d310b02971e3a1bb12a
2018-01-12 15:35:43 +00:00
Badhri Jagan Sridharan
65a6237243 Overcome disconnect during oem override
Cherry-pick from 83a0d6fa57

While bootup, usb gets configured when the property triggers are
run. While in oemOverride, the current configuration is persisted
in sys.usb.<bootmode>.config. Do not reconfigure the stack if the
current configuration is same as the new configuration.

Bug: 64225494
Change-Id: Id35d110bf3fa8f58d05e14941716d4ad2b196f8d
2018-01-10 16:45:32 -08:00
Jerry Zhang
30b9adfad1 Add setScreenUnlockedFunctions method to UsbManager
The screen unlocked functions save effort on setting
the usb config during each connection. These
functions persist between connections and between
boots. When the screen is unlocked and these
functions are set, the current functions will
be automatically set to the screen unlocked functions.

Also added svc command for this so it can be
used and tested while the UI is worked on.

Bug: 62876645
Test: svc usb setScreenUnlockedFunctions mtp
Test: Test functions with locking, unlocking, and
disconnecting, with no lockscreen, swipe, and pattern

Change-Id: Ia05e095917166d25398c4d310b02971e3a1bb12a
2018-01-09 15:36:35 -08:00
Paul McLean
f25c4eb7fd Adding ability to control how the USB data is dumped.
Also added tracing to android.UsbDevice creation.

Test: Try each dump command with CALYX Pat USB DAC & Dragonfly Red USB DAC

Change-Id: I2ec05dfa9c544d0c50ee59e3b990e9010cbe0aa0
2017-12-13 13:33:40 -07:00
Paul McLean
2b3ae20bfc Saving USB Device connect/disconnect info.
Test: Manual testing with Skylab, Mir, HTC dongle & Presonus AudioBox 22VSL
  (and various others)

Change-Id: Ice1bb889bc4655805d6b117988a5ebc4baa48cde
2017-12-06 09:49:22 -08:00
Paul McLean
558ff9d3f5 Fixed class and subclass IDs sign extension on byte->int problem.
Devices - Skylab, Mir, HTC dongle, Presonus AudioBox 44VSL, HP mouse
Hard coded class ID of 0xFF and subclass 0xFD to match b/68944518 symptoms.

Bug: 68944518

Test: Manual - see above

Change-Id: I7330c57b15278158a2eb449f0463b91244a3e176
2017-11-27 20:58:38 -07:00
Paul Mclean
9d84fee2ea Revert "Revert "Eliminate native/JNI/callback USB Descriptor parsing mechanism""
This reverts commit 115cd64f16.

Change-Id: I8be17cf939397b3c8ac6b11759b8195f5febab10
2017-11-27 20:58:38 -07:00
Emilian Peev
c8ed5ecdc4 Check camera permissions for any devices using the VIDEO class
Any USB devices that are of class VIDEO or have similar
interfaces should check whether the calling client has
camera permissions before granting access to the device.
The above restriction will apply for any packages that
target P or above.

Bug: 27367690
Test: Manual using 3-rd party USB webcam applications.
Change-Id: I7b4f808d344cae33fde93e6d81c7cceed523e24a
2017-11-16 09:00:00 +00:00
Xin Li
220871a697 Merge commit '98e12851336b7db16e583f9afac63ecc97465980' from
oc-mr1-dev-plus-aosp-without-vendor into stage-aosp-master.

Change-Id: Ia7b8da4a00d215160e4a4fa40f6044208d1297b7
Merged-In: I19846d2a3ee27aecbae2367a74ee49082eea154d
2017-11-14 12:31:11 -08:00