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 89:
Line 89:
| Just displays an error-code.
| Just displays an error-code.
| Yes
| Yes
+
| 0100000000001010
+
|
+
|-
+
| NsoApplet
+
| Nintendo Switch Online menu
+
|
+
|
| 0100000000001010
| 0100000000001010
|
|
Line 160:
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 209:
Line 221:
The size used by title 010000000000100A (on 10.0.0 at least) is 0x14200000.
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).
+
+
<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 ==
Line 263:
Line 281:
| 7
| 7
| Lobby
| Lobby
+
|-
+
| 8
+
| [[#NsoApplet|Lhub]]
|}
|}
Line 270:
Line 291:
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
Next info was tested in 9.0.0
−
In the js side, 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 succesful 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
+
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 will crash.
+
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 313:
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 324:
Line 345:
|}
|}
−
==== IDs ====
+
==== WebSessionSendMessageKind ====
+
This is "nn::web::detail::WebSessionSendMessageKind".
+
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 333:
Line 356:
| 0x0
| 0x0
| Arbitrary
| Arbitrary
−
| Arbitrary content. Used to communicate with the applet via JsExtensions used by the Js being run by the applet on the current page.
+
| 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
−
| 0xc
+
| 0xC
| Ack. Content: first u32 is the entire storage size of the message being acked, the rest is not used.
| 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 874:
Line 923:
| u8 bool
| u8 bool
| MediaPlayerUiEnabled
| MediaPlayerUiEnabled
+
|-
+
| [11.0.0+]
+
|
+
| 0x44
+
| 0x1
+
| bool
+
| TransferMemoryEnabled
|}
|}
Line 886:
Line 942:
[6.0.0+] <code>AddAlbumEntryAndMediaData</code> was added:
[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.
* 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 1,122:
Line 1,180:
==== WebSessionBootMode ====
==== WebSessionBootMode ====
+
This is "nn::web::WebSessionBootMode".
+
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 1,130:
Line 1,190:
| 0
| 0
|
|
−
| Normal (AllForeground)
+
| Normal/default (AllForeground)
|-
|-
| 1
| 1