Line 1: |
Line 1: |
| Nintendo Switch does not have a normal Internet Browser for user usage. However, there is multiple browser applets. It is the [https://web.archive.org/web/20170304075230/https://gl.access-company.com/news_event/archives/2017/170303/ NetFront NX] browser, which is based on Webkit. | | Nintendo Switch does not have a normal Internet Browser for user usage. However, there is multiple browser applets. It is the [https://web.archive.org/web/20170304075230/https://gl.access-company.com/news_event/archives/2017/170303/ NetFront NX] browser, which is based on Webkit. |
| | | |
− | When linking the Nintendo Account with Facebook, the Facebook Auth website will open, offering a search box that can be used to browse the Internet ("LoginApplet"). Alternatively, it can be accessed with [https://gbatemp.net/threads/web-browser-kind-of-on-the-switch.463094/ custom DNS settings] which simulate a Wi-Fi login page ("WifiWebAuthApplet" for captive-portal). | + | When linking the Nintendo Account with Facebook, the Facebook Auth website will open, offering a search box that can be used to browse the Internet ("LoginApplet"). Alternatively, it can be accessed with custom DNS settings which simulate a Wi-Fi login page ([[#WifiWebAuthApplet|WifiWebAuthApplet]] for captive-portal). |
| | | |
| == Known User Agent Strings == | | == Known User Agent Strings == |
Line 34: |
Line 34: |
| | [[6.1.0]] | | | [[6.1.0]] |
| | Mozilla/5.0 (Nintendo Switch; <appletname>) AppleWebKit/601.6 (KHTML, like Gecko) NF/4.0.0.10.14 NintendoBrowser/5.1.0.17806 | | | Mozilla/5.0 (Nintendo Switch; <appletname>) AppleWebKit/601.6 (KHTML, like Gecko) NF/4.0.0.10.14 NintendoBrowser/5.1.0.17806 |
| + | |- |
| + | | [[10.0.0]] |
| + | | Mozilla/5.0 (Nintendo Switch; <appletname>) AppleWebKit/606.4 (KHTML, like Gecko) NF/6.0.1.15.4 NintendoBrowser/5.1.0.20389 |
| |} | | |} |
| | | |
Line 86: |
Line 89: |
| | Just displays an error-code. | | | Just displays an error-code. |
| | Yes | | | Yes |
| + | | 0100000000001010 |
| + | | |
| + | |- |
| + | | NsoApplet |
| + | | Nintendo Switch Online menu |
| + | | |
| + | | |
| | 0100000000001010 | | | 0100000000001010 |
| | | | | |
Line 120: |
Line 130: |
| | | |
| Prior to version [[3.0.0]], this applet was launched when attempting a system update from recovery mode if needed. This was changed to display a "This feature is not available." popup instead. | | Prior to version [[3.0.0]], this applet was launched when attempting a system update from recovery mode if needed. This was changed to display a "This feature is not available." popup instead. |
| + | |
| + | The conntest URL from [[#WebWifiPageArg]] is used to poll whether the connection is usable, with the SDK [[libcurl]]. |
| | | |
| ==Whitelisted Applets== | | ==Whitelisted Applets== |
Line 155: |
Line 167: |
| You can invite friends to the room via | | You can invite friends to the room via |
| the Nintendo Switch Online Lounge app. | | the Nintendo Switch Online Lounge app. |
| + | |
| + | === NsoApplet === |
| + | [11.0.0+] This applet handles the new Nintendo Switch Online menu, which is launched from qlaunch. |
| + | |
| + | The initial page loaded by this applet is: <nowiki>"https://%.nso.nintendo.net/</nowiki>{string from [[#TLVs|TLV]] 0x2}" |
| | | |
| == ShopN == | | == ShopN == |
Line 201: |
Line 218: |
| | | |
| == Heap == | | == Heap == |
| + | The size used for [[SVC|svcSetHeapSize]] by the web-applets is 0x15600000. Under ShopN, the largest size that can be passed to this without an error being returned, is 0x1B400000. |
| + | |
| + | The size used by title 010000000000100A (on 10.0.0 at least) is 0x14200000. |
| + | |
| + | The heap for the main-codebin (<code>malloc</code>/<code>operator new</code>) uses nn::lmem::*ExpHeap. [8.0.0+] <code>malloc</code>/<code>operator new</code> now checks the return-addr (addr located in a relevant NRO), with wkc_malloc_crashonfailure being called for the allocation if the check passes, otherwise a normal allocation is done (the code which runs for this will Abort if allocation fails). |
| | | |
− | The size used for [[SVC|svcSetHeapSize]] by the web-applets is 0x15600000. Under ShopN, the largest size that can be passed to this without an error being returned, is 0x1B400000. | + | <code>malloc</code> passes the input size directly to the called func. <code>operator new</code> when handling normal non-wkc allocations passes the following to the called func: <code>sxtw x1, {inw0}</code> (for wkc allocations the size is passed directly). [12.1.0+] The size is now passed directly (64bit) without using sxtw. |
| + | |
| + | [11.0.0+] There's now optional code for using [[SVC|svcMapPhysicalMemoryUnsafe]] etc, however it's unknown what sets the flag for this. An Abort string used this is: "{path}/TransferredMemoryManager.cpp" |
| | | |
| == Applet Launching == | | == Applet Launching == |
− | The web-applets are launched using a storage containing the input arg data, on exit the output storage contains the "*ReturnValue" reply data struct. The output struct is specific to each applet. | + | The web-applets are launched using a storage containing the input arg data, on exit the output storage contains the "*ReturnValue" reply data. |
| + | |
| + | Input/output storage size for TLV data is 0x2000-bytes. |
| | | |
| === Library Applet Versions === | | === Library Applet Versions === |
Line 217: |
Line 243: |
| |- | | |- |
| | [5.0.0+] || 0x50000 | | | [5.0.0+] || 0x50000 |
| + | |- |
| + | | [6.0.0+] || 0x60000 |
| + | |- |
| + | | [8.0.0+] || 0x80000 |
| |} | | |} |
| | | |
Line 236: |
Line 266: |
| | 2 | | | 2 |
| | Login | | | Login |
| + | |- |
| + | | 3 |
| + | | Offline |
| |- | | |- |
| | 4 | | | 4 |
Line 248: |
Line 281: |
| | 7 | | | 7 |
| | Lobby | | | Lobby |
| + | |- |
| + | | 8 |
| + | | [[#NsoApplet|Lhub]] |
| |} | | |} |
| | | |
| === WebSession === | | === WebSession === |
− | With [5.0.0+] sdk-nso added <code>nn::web::Session::</code>. WebApplet (Web shim title) doesn't seem to implement this, unknown if other titles do. | + | With [5.0.0+] sdk-nso added <code>nn::web::Session::</code>. With [6.0.0+] this was removed, however it was reintroduced with [7.0.0+] as <code>nn::web::*WebSession</code> (for ShimKind Offline and Web). |
| | | |
| This is for sending/receiving [[#SessionMessage]]s via applet Interactive storage. | | This is for sending/receiving [[#SessionMessage]]s via applet Interactive storage. |
| | | |
− | During state init, max_messages is set to 0xA and max_size is set to 0x5000, with message_count=0 and cur_size=0. | + | During state init, max_messages is set to 0xA ([7.0.0+] 0x10), with message_count=0 and cur_size=0. [5.0.0-5.1.0] max_size is set to 0x5000. [7.0.0+] Two queues are used for message_count/cur_size: first one is for BrowserEngineContent (max_size 0x8000 is used), the second one is for non-BrowserEngineContent (max_size 0x1000 is used). |
| | | |
− | When sending messages, there has to be an available message slot available (<code>max_messages!=message_count</code>), and there has to be enough space avilable (<code>msghdr_contentsize+0x10 + cur_size <= max_size</code>). After pushing the storage, message_count is incremented and cur_size is increased by <code>msghdr_contentsize+0x10</code>. | + | When sending messages, there has to be an available message slot available (<code>max_messages!=message_count</code>), and there has to be enough space available (<code>msghdr_contentsize+0x10 + cur_size <= max_size</code>). After pushing the storage, message_count is incremented and cur_size is increased by <code>msghdr_contentsize+0x10</code>. |
| | | |
− | When receiving messages, it will repeatedly pop Interactive output storage until no more are available. If the ID is not 0x1000/0x0, the message is ignored. Otherwise: | + | When receiving messages, it will repeatedly pop Interactive output storage until no more are available. Non-Ack messages are Acked. |
| * Ack: Verifies that message_count is not already 0, then decrements it. Then cur_size is decreased by the u32 loaded from msgcontent+0. | | * Ack: Verifies that message_count is not already 0, then decrements it. Then cur_size is decreased by the u32 loaded from msgcontent+0. |
− | * 0x0: Does some validation. Copies the first 8-bytes from the header to the user [[#SessionMessage]]. Reads the message content into the user [[#SessionMessage]], when contentsize is non-zero. Then sends an Ack with the storage size. | + | * 0x0: Does some validation. Reads the message content into the user buffer, when contentsize is non-zero. The original contentsize is written to an user output param. The last byte in the user buffer (contentsize clamped to the user max-buf-size, -1) is set to 0 for NUL-termination. |
| + | |
| + | Next info was tested in 9.0.0 |
| + | |
| + | In the js side (which is only available when enabled via the JsExtensionEnabled TLV), there is a method called <code>window.nx.sendMessage(arg)</code> that sends data to the native side, this method returns a boolean indicating if sending was successful and accepts a string as an argument. The string is encoded like a C null terminated string in the message content. For receive messages from native part, there is a dom event called <code>message</code> which is dispatched when a message arrives. The event can be listened using <code>window.nx.addEventListener("message", callback)</code> being callback a function which first parameter is like a dom event arg and contains a member called <code>data</code> which contains the string decoded from the arrived message. |
| + | |
| + | If messages aren't acked by the native part, js side will not longer receive messages. Ack to web applet '''must''' have 4 bytes after the message content or the applet will Abort. |
| | | |
| ==== SessionMessage ==== | | ==== SessionMessage ==== |
Line 277: |
Line 319: |
| | Size from header | | | Size from header |
| | Message content | | | Message content |
| + | |- |
| + | | After message content |
| + | | 0x4 if message is ack, 0x0 otherwise |
| + | | Padding |
| |} | | |} |
| | | |
Line 288: |
Line 334: |
| | 0x0 | | | 0x0 |
| | 0x4 | | | 0x4 |
− | | Message ID | + | | Message Kind ([[#WebSessionSendMessageKind]] / [[#WebSessionReceiveMessageKind]]) |
| |- | | |- |
| | 0x4 | | | 0x4 |
| | 0x4 | | | 0x4 |
− | | Content size following the header. | + | | Data size following the header. |
| |- | | |- |
| | 0x8 | | | 0x8 |
Line 299: |
Line 345: |
| |} | | |} |
| | | |
− | ==== IDs ==== | + | ==== WebSessionSendMessageKind ==== |
| + | This is "nn::web::detail::WebSessionSendMessageKind". |
| + | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
Line 308: |
Line 356: |
| | 0x0 | | | 0x0 |
| | Arbitrary | | | Arbitrary |
− | | Arbitrary content. | + | | BrowserEngine Content, NUL-terminated string. Used to communicate with the applet via JsExtensions used by the Js being run by the applet on the current page. |
| + | |- |
| + | | 0x100 |
| + | | 0x0 |
| + | | SystemMessage Appear. Requests the applet to Appear, this is only needed with [[#WebSessionBootMode]] AllForegroundInitiallyHidden. |
| |- | | |- |
| | 0x1000 | | | 0x1000 |
− | | 0x8 | + | | 0xC |
− | | Ack. Content: first u32 is the entire storage size of the message being acked, while the second u32 is 0. | + | | Ack. Content: first u32 is the entire storage size of the message being acked, the rest is not used. |
| + | |} |
| + | |
| + | ==== WebSessionReceiveMessageKind ==== |
| + | This is "nn::web::detail::WebSessionReceiveMessageKind". |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! ID |
| + | ! Content size |
| + | ! Description |
| + | |- |
| + | | 0x0 |
| + | | Arbitrary |
| + | | BrowserEngine Content, see [[#WebSessionSendMessageKind]]. |
| + | |- |
| + | | 0x1000 |
| + | | 0xC |
| + | | Ack BrowserEngine |
| + | |- |
| + | | 0x1001 |
| + | | 0xC |
| + | | Ack SystemMessage |
| |} | | |} |
| | | |
Line 367: |
Line 441: |
| |} | | |} |
| | | |
− | This is the 0x1010-byte output storage used by all non-WebWifi applets - except for Share which returns a TLV storage on [3.0.0+]. | + | This is the 0x1010-byte output storage used by all non-WebWifi applets - except for Share which returns a TLV storage on [3.0.0+], and Web on [8.0.0+]. |
| | | |
| === WebArgHeader === | | === WebArgHeader === |
Line 401: |
Line 475: |
| Web TLV used in the input web Arg storage, after [[#WebArgHeader]]. This is a total of 0x8-bytes. | | Web TLV used in the input web Arg storage, after [[#WebArgHeader]]. This is a total of 0x8-bytes. |
| | | |
| + | === WebBootFooterButtonEntry === |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | 0x0 || 0x4 || [[#FooterButtonId]] |
| + | |- |
| + | | 0x4 || 0x1 || u8 bool visible flag |
| + | |- |
| + | | 0x5 || 0x2 || ? |
| + | |- |
| + | | 0x7 || 0x1 || ? |
| + | |} |
| | | |
| === TLVs === | | === TLVs === |
Line 497: |
Line 586: |
| | 0x20 | | | 0x20 |
| | [[Capture_services|AlbumEntry]] | | | [[Capture_services|AlbumEntry]] |
− | | AlbumEntry | + | | AlbumEntry0 |
| |- | | |- |
| | [1.0.0+] | | | [1.0.0+] |
Line 623: |
Line 712: |
| | 0x1 | | | 0x1 |
| | u8 bool | | | u8 bool |
− | | MediaPlayerUserGestureRestrictionEnabled | + | | [6.0.0+] MediaAutoPlayEnabled ([2.0.0-5.1.0] MediaPlayerUserGestureRestrictionEnabled) |
| |- | | |- |
| | [2.0.0+] | | | [2.0.0+] |
Line 672: |
Line 761: |
| | 0x10 | | | 0x10 |
| | u8 array | | | u8 array |
− | | AdditionalMediaData (If the user-input size is less than 0x10, the remaining tmp data used for the TLV is cleared) | + | | AdditionalMediaData0 (If the user-input size is less than 0x10, the remaining tmp data used for the TLV is cleared) |
| |- | | |- |
| | [4.0.0+] | | | [4.0.0+] |
Line 743: |
Line 832: |
| | u8 bool | | | u8 bool |
| | PageScrollIndicatorEnabled | | | PageScrollIndicatorEnabled |
| + | |- |
| + | | [6.0.0+] |
| + | | |
| + | | 0x37 |
| + | | 0x1 |
| + | | u8 bool |
| + | | MediaPlayerSpeedControlEnabled |
| + | |- |
| + | | [6.0.0+] |
| + | | Share |
| + | | 0x38 |
| + | | 0x20 |
| + | | [[Capture_services|AlbumEntry]] |
| + | | AlbumEntry1 |
| + | |- |
| + | | [6.0.0+] |
| + | | Share |
| + | | 0x39 |
| + | | 0x20 |
| + | | [[Capture_services|AlbumEntry]] |
| + | | AlbumEntry2 |
| + | |- |
| + | | [6.0.0+] |
| + | | Share |
| + | | 0x3A |
| + | | 0x20 |
| + | | [[Capture_services|AlbumEntry]] |
| + | | AlbumEntry3 |
| + | |- |
| + | | [6.0.0+] |
| + | | Share |
| + | | 0x3B |
| + | | 0x10 |
| + | | u8 array |
| + | | AdditionalMediaData1 |
| + | |- |
| + | | [6.0.0+] |
| + | | Share |
| + | | 0x3C |
| + | | 0x10 |
| + | | u8 array |
| + | | AdditionalMediaData2 |
| + | |- |
| + | | [6.0.0+] |
| + | | Share |
| + | | 0x3D |
| + | | 0x10 |
| + | | u8 array |
| + | | AdditionalMediaData3 |
| + | |- |
| + | | [6.0.0+] |
| + | | BootFooterButton |
| + | | 0x3E |
| + | | 0x80 |
| + | | Array of [[#WebBootFooterButtonEntry]] with 0x10 entries. |
| + | | BootFooterButton |
| + | |- |
| + | | [6.0.0+] |
| + | | |
| + | | 0x3F |
| + | | 0x4 |
| + | | float |
| + | | OverrideWebAudioVolume |
| + | |- |
| + | | [6.0.0+] |
| + | | |
| + | | 0x40 |
| + | | 0x4 |
| + | | float |
| + | | OverrideMediaAudioVolume |
| + | |- |
| + | | [7.0.0+] |
| + | | |
| + | | 0x41 |
| + | | 0x4 |
| + | | u32 enum [[#WebSessionBootMode]] |
| + | | BootMode |
| + | |- |
| + | | [7.0.0+] |
| + | | |
| + | | 0x42 |
| + | | 0x1 |
| + | | u8 bool |
| + | | Enables using [[#WebSession]] when set. |
| + | |- |
| + | | [8.0.0+] |
| + | | Offline |
| + | | 0x43 |
| + | | 0x1 |
| + | | u8 bool |
| + | | MediaPlayerUiEnabled |
| + | |- |
| + | | [11.0.0+] |
| + | | |
| + | | 0x44 |
| + | | 0x1 |
| + | | bool |
| + | | TransferMemoryEnabled |
| |} | | |} |
| | | |
| Offline: title to load the content from is controlled by ApplicationId/SystemDataId. With DocumentKind_OfflineHtmlPage, it will ignore this and only load from the user-process title. | | Offline: title to load the content from is controlled by ApplicationId/SystemDataId. With DocumentKind_OfflineHtmlPage, it will ignore this and only load from the user-process title. |
| | | |
− | Offline DocumentPath: Initial document path in RomFS, without the leading '/'. For DocumentKind_OfflineHtmlPage, this is relative to "html-document/" in RomFS. For the other DocumentKind values, this is relative to "/" in RomFS. | + | Offline DocumentPath: Initial document path in RomFS, without the leading '/'. For DocumentKind_OfflineHtmlPage, this is relative to "html-document/" in RomFS. For the other DocumentKind values, this is relative to "/" in RomFS. This path must contain ".htdocs/". |
| | | |
| Share/Lobby: if a non-zero userID isn't set, the applet will launch the profile-selector applet to select an account. | | Share/Lobby: if a non-zero userID isn't set, the applet will launch the profile-selector applet to select an account. |
| | | |
| Share: An error will be displayed if neither AlbumEntry or ApplicationAlbumEntry are set, with [[#ShareStartPage|ShareStartPage_Default]]. | | Share: An error will be displayed if neither AlbumEntry or ApplicationAlbumEntry are set, with [[#ShareStartPage|ShareStartPage_Default]]. |
| + | |
| + | [6.0.0+] <code>AddAlbumEntryAndMediaData</code> was added: |
| + | * Looks for AlbumEntry{N} TLVs, when a TLV is not found it is written, then the associated AdditionalMediaData{N} TLV is written the same way as AdditionalMediaData0. If all AlbumEntry{N} TLVs already exist, this returns without writing anything. |
| + | |
| + | TransferMemoryEnabled: sdknso only exposes this for the Web applet. The sdknso func uses <code>nn::os::QueryMemoryInfo</code> at the start of the func, however the output is unused. The applet doesn't seem to parse this TLV. |
| | | |
| ==== Output TLVs ==== | | ==== Output TLVs ==== |
Line 757: |
Line 949: |
| |- | | |- |
| ! System Version | | ! System Version |
| + | ! Applets |
| ! Type | | ! Type |
| ! Size | | ! Size |
Line 763: |
Line 956: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share, Web |
| | 0x1 | | | 0x1 |
| | 0x4 | | | 0x4 |
Line 769: |
Line 963: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share, Web |
| | 0x2 | | | 0x2 |
| | | | | |
Line 775: |
Line 970: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share, Web |
| | 0x3 | | | 0x3 |
| | 0x8 | | | 0x8 |
Line 781: |
Line 977: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share |
| | 0x4 | | | 0x4 |
| | 0x4 | | | 0x4 |
Line 787: |
Line 984: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share |
| | 0x5 | | | 0x5 |
| | | | | |
Line 793: |
Line 991: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share |
| | 0x6 | | | 0x6 |
| | 0x8 | | | 0x8 |
Line 799: |
Line 998: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share |
| | 0x7 | | | 0x7 |
| | | | | |
Line 805: |
Line 1,005: |
| |- | | |- |
| | [3.0.0+] | | | [3.0.0+] |
| + | | Share |
| | 0x8 | | | 0x8 |
| | 0x8 | | | 0x8 |
| | u64 | | | u64 |
| | PostIdSize | | | PostIdSize |
| + | |- |
| + | | [8.0.0+] |
| + | | Web |
| + | | 0x9 |
| + | | 0x1 |
| + | | u8 bool |
| + | | MediaPlayerAutoClosedByCompletion |
| |} | | |} |
| | | |
− | These are used for Share-applet. Official user-processes doesn't check the TLV size for any of these. | + | These are used for Share-applet on [3.0.0+], and with Web on [8.0.0+]. Official user-processes doesn't check the TLV size for any of these. |
| | | |
| ==== DocumentKind ==== | | ==== DocumentKind ==== |
Line 929: |
Line 1,137: |
| | | |
| Controls the initial mode, this can be toggled by the user via the pressing the left-stick button. If the Pointer flag is set to false, only LeftStickMode_Cursor will be used and mode toggle by the user is disabled (input value ignored). | | Controls the initial mode, this can be toggled by the user via the pressing the left-stick button. If the Pointer flag is set to false, only LeftStickMode_Cursor will be used and mode toggle by the user is disabled (input value ignored). |
| + | |
| + | ==== FooterButtonId ==== |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Value |
| + | ! Name |
| + | ! Description |
| + | |- |
| + | | 0 |
| + | | None |
| + | | None, for empty [[#WebBootFooterButtonEntry]]. Invalid for use as an input Id. |
| + | |- |
| + | | 1 |
| + | | |
| + | | |
| + | |- |
| + | | 2 |
| + | | |
| + | | |
| + | |- |
| + | | 3 |
| + | | |
| + | | |
| + | |- |
| + | | 4 |
| + | | |
| + | | |
| + | |- |
| + | | 5 |
| + | | |
| + | | |
| + | |- |
| + | | 6 |
| + | | |
| + | | |
| + | |- |
| + | | 7 |
| + | | |
| + | | Values starting with this are invalid. |
| + | |- |
| + | |} |
| + | |
| + | ==== WebSessionBootMode ==== |
| + | This is "nn::web::WebSessionBootMode". |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Value |
| + | ! Name |
| + | ! Description |
| + | |- |
| + | | 0 |
| + | | |
| + | | Normal/default (AllForeground) |
| + | |- |
| + | | 1 |
| + | | |
| + | | AllForegroundInitiallyHidden |
| + | |} |
| + | |
| + | This controls which [[Applet_Manager_services|LibraryAppletMode]] the applet will be launched with, by the user-process. The TLV for this seems to be ignored by the applet. |
| | | |
| ==== LastUrl ==== | | ==== LastUrl ==== |