Skip to content

Commit c41361e

Browse files
authored
Merge branch 'ArmDeveloperEcosystem:main' into main
2 parents a0740a3 + 8138393 commit c41361e

134 files changed

Lines changed: 1239 additions & 147 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
108 KB
Loading
31.4 KB
Loading

content/install-guides/flatpak.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ official_docs: "https://docs.flatpak.org/en/latest/"
55
author: "Jason Andrews"
66
description: "Install Flatpak on Arm Linux, add the Flathub remote, and verify the setup by installing and running a native aarch64 application."
77
weight: 1
8-
draft: true
98
tool_install: true
109
layout: installtoolsall
1110
multi_install: false

content/install-guides/performix.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ On the target system, edit the sudoers file:
226226
sudo visudo
227227
```
228228

229-
Add the following line, replacing `<username>` with your actual username:
229+
Add the following line, replacing `<username>` with your actual username. Insert it after any existing entries for that user or their groups, since rules in the sudoers file are applied in order and later entries take precedence.
230230

231231
```bash
232232
<username> ALL=(ALL) NOPASSWD:ALL
@@ -287,6 +287,19 @@ Select **Add** to save the jump node.
287287

288288
You can add multiple jump nodes. The order matters—your connection uses them in sequence. Use drag and drop to reorder jump nodes.
289289

290+
#### Connect using the Arm Performix GUI to a local machine
291+
292+
Performix already includes a built-in `localhost` target through the CLI. However, as of Performix 2026.01, this target is not exposed in the GUI. If you prefer the command line, you can run recipes directly without configuring the target through the GUI. [Skip to the profile the local machine section](#profile-the-local-machine) below.
293+
294+
If you want to target your local machine conveniently through the GUI, use `localhost` in place of `target_host` and select **Username and password** as the authentication method, as shown in the following image. Make sure passwordless `sudo` is enabled for your user account.
295+
296+
297+
![Arm Performix GUI showing the Configure Target form for a local connection using 'localhost', including Host set to localhost, Name field for a custom label, Port set to 22, User set to the local username, authentication set to Username and password, and Host Key Verification options#center](/install-guides/_images/connect-via-local-host.png "Configure local target using localhost in Arm Performix GUI")
298+
299+
Enter the password for your user when prompted
300+
301+
![Arm Performix GUI displaying a password prompt dialog requesting the user's system password for authentication, including a password input field, confirmation button, and context indicating connection to a localhost target#center](/install-guides/_images/performix-add-passwrd.png "Enter user password for localhost authentication in Arm Performix")
302+
290303
### Connect using the Arm Performix CLI
291304

292305
The CLI is useful for Linux hosts or when you prefer command-line workflows.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
title: Add an LLM to your Android app with Arm's AI Chat library
3+
draft: true
4+
cascade:
5+
draft: true
6+
7+
minutes_to_complete: 15
8+
9+
who_is_this_for: This is an introductory topic for developers who want to add a local, on-device LLM chat experience using Arm's AI Chat library, Kotlin, and Android Studio.
10+
11+
learning_objectives:
12+
- Create a simple Android chatbot app scaffold in Android Studio
13+
- Load a mobile-friendly GGUF model on-device and run streamed chat inference
14+
15+
prerequisites:
16+
- Android Studio
17+
- Android phone for testing (in Developer Mode, with USB cable to connect)
18+
19+
author: Ben Clark
20+
21+
### Tags
22+
skilllevels: Introductory
23+
subjects: ML
24+
armips:
25+
- Arm AI Chat library
26+
tools_software_languages:
27+
- Kotlin
28+
- Neon
29+
- SVE2
30+
- SME2
31+
- LLM
32+
operatingsystems:
33+
- Android
34+
35+
36+
37+
further_reading:
38+
- resource:
39+
title: AI Chat - Explore and evaluate LLMs on Android and ChromeOS
40+
link: https://developer.arm.com/community/arm-community-blogs/b/announcements/posts/ai-chat-explore-and-evaluate-llms-on-android-and-chromeos
41+
type: blog
42+
- resource:
43+
title: Arm AI Chat LLM test app
44+
link: https://play.google.com/store/apps/details?id=com.arm.aichat
45+
type: example app
46+
- resource:
47+
title: AI Chat library @ Maven Central
48+
link: https://central.sonatype.com/artifact/com.arm/ai-chat
49+
type: documentation
50+
- resource:
51+
title: AI Chat library on GitHub
52+
link: https://github.com/arm/ai-chat
53+
type: website
54+
- resource:
55+
title: Arm KleidiAI - Helping AI frameworks elevate their performance on Arm CPUs
56+
link: https://developer.arm.com/community/arm-community-blogs/b/ai-blog/posts/kleidiai
57+
type: blog
58+
- resource:
59+
title: SME2
60+
link: https://www.arm.com/technologies/sme2
61+
type: website
62+
63+
64+
### FIXED, DO NOT MODIFY
65+
# ================================================================================
66+
weight: 1 # _index.md always has weight of 1 to order correctly
67+
layout: "learningpathall" # All files under learning paths have this same wrapper
68+
learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content.
69+
---
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# ================================================================================
3+
# FIXED, DO NOT MODIFY THIS FILE
4+
# ================================================================================
5+
weight: 21 # The weight controls the order of the pages. _index.md always has weight 1.
6+
title: "Next Steps" # Always the same, html page title.
7+
layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing.
8+
---
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: Add AI Chat Library
3+
weight: 3
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Your freshly created Android Studio project should already have top-level repositories including `google()` and `mavenCentral()` in `settings.gradle.kts`, but check that it does, to ensure the app can find the library.
10+
11+
## Add the Maven Dependency
12+
We need to add the AI Chat library in the app module build file, `app/build.gradle.kts` (not the project `build.gradle.kts` in the root of the project).
13+
14+
In here we add into the `dependencies` section at the bottom:
15+
```kotlin
16+
implementation("com.arm:ai-chat:0.1.0")
17+
```
18+
19+
This adds the library to your project, and all the LLM functionality. Also in this file, check that:
20+
- `targetSdk` and `compileSdk` are 36
21+
- the Java version in `compileOptions` is `JavaVersion.VERSION_17`
22+
- the `jvmTarget` in `kotlinOptions` is 17
23+
24+
In `libs.version.toml`, check that:
25+
- `kotlin` version is `2.2.20`
26+
27+
Finally, there will be a banner at the top of these settings files saying the "Gradle files have changed since last project sync." Choose the option to "Sync Now", and let the project update.
28+
29+
## Adjust the Manifest
30+
We need to adjust the `AndroidManifest.xml` file, which is in `app\src\main`.
31+
32+
Most of the file is an xml tag `<application ...>`. Within the tag are several `android:` options. Add in an additional flag to load the needed llama.cpp native libraries:
33+
```xml
34+
<application
35+
...
36+
android:extractNativeLibs="true"
37+
... >
38+
```
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
---
2+
title: Add UI Code
3+
weight: 4
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
## Add Layouts
10+
Currently the `activity_main.xml` layout file in your `app\src\main\res\layout` directory is nearly empty, containing just a "Hello World!" piece of text that we wish to remove. Instead, replace it with the following, which will create a status area at the top, a place for messages in the middle, and a place for you to type at the bottom with a button to send:
11+
```xml
12+
<?xml version="1.0" encoding="utf-8"?>
13+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
14+
xmlns:app="http://schemas.android.com/apk/res-auto"
15+
android:id="@+id/root"
16+
android:layout_width="match_parent"
17+
android:layout_height="match_parent">
18+
19+
<TextView
20+
android:id="@+id/status_text"
21+
android:layout_width="0dp"
22+
android:layout_height="wrap_content"
23+
android:layout_marginStart="16dp"
24+
android:layout_marginTop="16dp"
25+
android:layout_marginEnd="16dp"
26+
android:text="Loading model..."
27+
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
28+
app:layout_constraintEnd_toEndOf="parent"
29+
app:layout_constraintStart_toStartOf="parent"
30+
app:layout_constraintTop_toTopOf="parent" />
31+
32+
<androidx.recyclerview.widget.RecyclerView
33+
android:id="@+id/messages"
34+
android:layout_width="0dp"
35+
android:layout_height="0dp"
36+
android:layout_marginStart="16dp"
37+
android:layout_marginTop="12dp"
38+
android:layout_marginEnd="16dp"
39+
android:clipToPadding="false"
40+
android:paddingBottom="8dp"
41+
app:layout_constraintBottom_toTopOf="@+id/input_row"
42+
app:layout_constraintEnd_toEndOf="parent"
43+
app:layout_constraintStart_toStartOf="parent"
44+
app:layout_constraintTop_toBottomOf="@+id/status_text" />
45+
46+
<LinearLayout
47+
android:id="@+id/input_row"
48+
android:layout_width="0dp"
49+
android:layout_height="wrap_content"
50+
android:layout_margin="16dp"
51+
android:orientation="horizontal"
52+
app:layout_constraintBottom_toBottomOf="parent"
53+
app:layout_constraintEnd_toEndOf="parent"
54+
app:layout_constraintStart_toStartOf="parent">
55+
<EditText
56+
android:id="@+id/user_input"
57+
android:layout_width="0dp"
58+
android:layout_height="wrap_content"
59+
android:layout_weight="1"
60+
android:enabled="false"
61+
android:hint="Model is loading..."
62+
android:inputType="textMultiLine"
63+
android:maxLines="4"
64+
android:minHeight="48dp"
65+
android:padding="12dp" />
66+
<com.google.android.material.button.MaterialButton
67+
android:id="@+id/send_button"
68+
android:layout_width="wrap_content"
69+
android:layout_height="wrap_content"
70+
android:layout_marginStart="12dp"
71+
android:enabled="false"
72+
android:text="Import model" />
73+
</LinearLayout>
74+
</androidx.constraintlayout.widget.ConstraintLayout>
75+
```
76+
77+
We also need two small "helper" layouts to format the messages from the user and the AI assistant. In the `layout` folder alongside the main layout, first create `item_message_user.xml` and insert the following:
78+
```xml
79+
<?xml version="1.0" encoding="utf-8"?>
80+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
81+
android:layout_width="match_parent"
82+
android:layout_height="wrap_content"
83+
android:paddingTop="6dp"
84+
android:paddingBottom="6dp">
85+
86+
<TextView
87+
android:id="@+id/msg_content"
88+
android:layout_width="wrap_content"
89+
android:layout_height="wrap_content"
90+
android:layout_gravity="end"
91+
android:background="#D7F0FF"
92+
android:padding="12dp"
93+
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" />
94+
</FrameLayout>
95+
```
96+
97+
Then create `item_message_assistant.xml` and put the following as its contents:
98+
```xml
99+
<?xml version="1.0" encoding="utf-8"?>
100+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
101+
android:layout_width="match_parent"
102+
android:layout_height="wrap_content"
103+
android:paddingTop="6dp"
104+
android:paddingBottom="6dp">
105+
106+
<TextView
107+
android:id="@+id/msg_content"
108+
android:layout_width="wrap_content"
109+
android:layout_height="wrap_content"
110+
android:layout_gravity="start"
111+
android:background="#EFEFEF"
112+
android:padding="12dp"
113+
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" />
114+
</FrameLayout>
115+
```
116+
117+
## Add the MessageAdaptor class
118+
As a final bit of UI code, we add a `MessageAdapter.kt` code file to put our messages into the correct bit of layout. The file should sit alongside the `MainActivity` class that is auto-created with the project.
119+
120+
{{% notice Package name %}}
121+
The `package` name below has to match that of your project name. If you named your project `simpleaichat`, you can copy the block without changes. If you named your project differently as you started out this Learning Path, make sure you update it after populating the file.
122+
{{% /notice %}}
123+
124+
The file contents of `MessageAdapter.kt` are:
125+
126+
```kotlin
127+
package com.example.simpleaichat
128+
129+
import android.view.LayoutInflater
130+
import android.view.View
131+
import android.view.ViewGroup
132+
import android.widget.TextView
133+
import androidx.recyclerview.widget.RecyclerView
134+
135+
data class Message(
136+
val id: String,
137+
val content: String,
138+
val isUser: Boolean
139+
)
140+
141+
class MessageAdapter(
142+
private val messages: List<Message>
143+
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
144+
145+
override fun getItemViewType(position: Int): Int {
146+
return if (messages[position].isUser) VIEW_TYPE_USER else VIEW_TYPE_ASSISTANT
147+
}
148+
149+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
150+
val inflater = LayoutInflater.from(parent.context)
151+
return if (viewType == VIEW_TYPE_USER) {
152+
UserMessageViewHolder(inflater.inflate(R.layout.item_message_user, parent, false))
153+
} else {
154+
AssistantMessageViewHolder(inflater.inflate(R.layout.item_message_assistant, parent, false))
155+
}
156+
}
157+
158+
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
159+
holder.itemView.findViewById<TextView>(R.id.msg_content).text = messages[position].content
160+
}
161+
162+
override fun getItemCount(): Int = messages.size
163+
164+
class UserMessageViewHolder(view: View) : RecyclerView.ViewHolder(view)
165+
class AssistantMessageViewHolder(view: View) : RecyclerView.ViewHolder(view)
166+
167+
companion object {
168+
private const val VIEW_TYPE_USER = 1
169+
private const val VIEW_TYPE_ASSISTANT = 2
170+
}
171+
}
172+
```
173+
174+
Quickly going through the important parts:
175+
- `Message` is the smallest useful chat piece: one id, the message text, and a flag saying whether it came from the user or the assistant.
176+
- `getItemViewType(...)` decides which row layout to use for each message.
177+
- `onCreateViewHolder(...)` inflates either the user bubble or the assistant bubble layout.
178+
- `onBindViewHolder(...)` writes the current message text into the row.
179+
- `getItemCount()` tells the `RecyclerView` how many chat rows it should render.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: Add Model And Run
3+
weight: 6
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
## Download a Mobile-compatible GGUF
10+
Before you run you'll need to download a GGUF model file to run. To be mobile compatible, it'll need to run within your test Android phone's memory. A common Android memory size is 8GB, although some modern premium phones have more. Other things will also need to fit in memory, so the model size will need to be noticeably less than 8GB.
11+
12+
A good example model is [google_gemma-3-4b-it-Q4_0.gguf](https://huggingface.co/bartowski/google_gemma-3-4b-it-GGUF/blob/main/google_gemma-3-4b-it-Q4_0.gguf). Gemma 3 is a powerful model, and this 4 billion parameter version has been int4 quantized with the Q4_0 schema that works particularly well with Arm's [KleidiAI library](https://developer.arm.com/ai/kleidi-libraries), enabling speed-ups on phones with [SME2](https://www.arm.com/technologies/sme2), [SVE2](https://developer.arm.com/documentation/102340/0100/Introducing-SVE2) and [Neon](https://www.arm.com/technologies/neon).
13+
14+
Download Gemma 3 or another suitable model onto your phone, ready to run the app.
15+
16+
## Run the App!
17+
In Android Studio, if you connect your test Android phone with a USB cable to your computer, you should now be able to run your LLM chatbot app. Make sure when you connect the phone it is in Developer Mode and you allow USB debugging.
18+
19+
In the bottom right there is a button "Import model". Clicking this will take you to downloads to be able to select the model you've downloaded, so the app can download it. Once it has finished copying and loading the model it will say "Model ready" at the top of the screen. Now if you click the text entry area at the bottom, you can type your questions and chat with the LLM.
20+
21+
![App screenshot#center](app_screenshot.jpg "Figure 1. AI Chat app screenshot interacting with Gemma 3 4B")
77 KB
Loading

0 commit comments

Comments
 (0)