or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-management.mddata-storage.mdencryption.mdindex.mdinitialization.mdinstance-management.mdmulti-process.mdnamespace.md

multi-process.mddocs/

0

# Multi-Process Operations

1

2

Safe multi-process access with file locking, content change notifications, and process-aware instance management for applications with multiple processes.

3

4

## Capabilities

5

6

### Process Mode Configuration

7

8

Configure MMKV instances for multi-process access with proper synchronization.

9

10

```java { .api }

11

/**

12

* Check if this instance is in multi-process mode.

13

* @return True if multi-process, false if single-process

14

*/

15

public boolean isMultiProcess();

16

17

/**

18

* Check if this instance is in read-only mode.

19

* @return True if read-only, false if read-write

20

*/

21

public boolean isReadOnly();

22

```

23

24

**Usage Example:**

25

26

```java

27

import com.tencent.mmkv.MMKV;

28

29

// Create multi-process instance

30

MMKV multiProcessKv = MMKV.mmkvWithID("shared_data", MMKV.MULTI_PROCESS_MODE);

31

32

// Create single-process instance

33

MMKV singleProcessKv = MMKV.mmkvWithID("local_data", MMKV.SINGLE_PROCESS_MODE);

34

35

// Create read-only instance

36

MMKV readOnlyKv = MMKV.mmkvWithID("config_data", MMKV.READ_ONLY_MODE);

37

38

// Check process modes

39

boolean isMulti = multiProcessKv.isMultiProcess(); // true

40

boolean isSingle = singleProcessKv.isMultiProcess(); // false

41

boolean isReadOnly = readOnlyKv.isReadOnly(); // true

42

43

Log.d("MMKV", String.format("Multi: %b, Single: %b, ReadOnly: %b",

44

isMulti, isSingle, isReadOnly));

45

```

46

47

### File Locking

48

49

Exclusive inter-process locking for critical sections that require atomic operations across processes.

50

51

```java { .api }

52

/**

53

* Exclusively inter-process lock the MMKV instance.

54

* Blocks and waits until it successfully locks the file.

55

* No effect if the instance is in SINGLE_PROCESS_MODE.

56

*/

57

public void lock();

58

59

/**

60

* Exclusively inter-process unlock the MMKV instance.

61

* No effect if the instance is in SINGLE_PROCESS_MODE.

62

*/

63

public void unlock();

64

65

/**

66

* Try exclusively inter-process lock the MMKV instance.

67

* Does not block if the file is already locked by another process.

68

* No effect if the instance is in SINGLE_PROCESS_MODE.

69

* @return True if successfully locked, false if already locked

70

*/

71

public boolean tryLock();

72

```

73

74

**Usage Example:**

75

76

```java

77

MMKV sharedKv = MMKV.mmkvWithID("shared_counter", MMKV.MULTI_PROCESS_MODE);

78

79

// Atomic increment operation across processes

80

public void incrementCounter() {

81

sharedKv.lock();

82

try {

83

int currentValue = sharedKv.decodeInt("counter", 0);

84

int newValue = currentValue + 1;

85

sharedKv.encode("counter", newValue);

86

Log.d("MMKV", "Counter incremented to: " + newValue);

87

} finally {

88

sharedKv.unlock();

89

}

90

}

91

92

// Non-blocking lock attempt

93

public boolean tryIncrementCounter() {

94

if (sharedKv.tryLock()) {

95

try {

96

int currentValue = sharedKv.decodeInt("counter", 0);

97

int newValue = currentValue + 1;

98

sharedKv.encode("counter", newValue);

99

Log.d("MMKV", "Counter incremented to: " + newValue);

100

return true;

101

} finally {

102

sharedKv.unlock();

103

}

104

} else {

105

Log.d("MMKV", "Could not acquire lock, counter not incremented");

106

return false;

107

}

108

}

109

```

110

111

### Content Change Notifications

112

113

Monitor changes made by other processes to shared MMKV instances.

114

115

```java { .api }

116

/**

117

* Check inter-process content change manually.

118

* Call this to detect if another process has modified the MMKV instance.

119

*/

120

public void checkContentChangedByOuterProcess();

121

122

/**

123

* Register for MMKV inter-process content change notification.

124

* The notification triggers only when methods are manually called on the MMKV instance.

125

* @param notify The notification handler

126

*/

127

public static void registerContentChangeNotify(MMKVContentChangeNotification notify);

128

129

/**

130

* Unregister for MMKV inter-process content change notification.

131

*/

132

public static void unregisterContentChangeNotify();

133

```

134

135

**Usage Example:**

136

137

```java

138

import com.tencent.mmkv.MMKVContentChangeNotification;

139

140

public class MultiProcessExample {

141

142

private MMKV sharedKv;

143

144

public void setupMultiProcessNotifications() {

145

// Register global content change notification

146

MMKV.registerContentChangeNotify(new MMKVContentChangeNotification() {

147

@Override

148

public void onContentChangedByOuterProcess(String mmapID) {

149

Log.d("MMKV", "Content changed in instance: " + mmapID);

150

// Handle the change - maybe refresh UI or reload data

151

handleContentChange(mmapID);

152

}

153

});

154

155

sharedKv = MMKV.mmkvWithID("shared_settings", MMKV.MULTI_PROCESS_MODE);

156

157

// Start periodic checking for changes

158

startPeriodicChangeCheck();

159

}

160

161

private void startPeriodicChangeCheck() {

162

Handler handler = new Handler(Looper.getMainLooper());

163

Runnable checkRunnable = new Runnable() {

164

@Override

165

public void run() {

166

// Check if content changed in other processes

167

sharedKv.checkContentChangedByOuterProcess();

168

169

// Schedule next check

170

handler.postDelayed(this, 5000); // Check every 5 seconds

171

}

172

};

173

handler.post(checkRunnable);

174

}

175

176

private void handleContentChange(String mmapID) {

177

if ("shared_settings".equals(mmapID)) {

178

// Reload settings that might have changed

179

reloadSharedSettings();

180

}

181

}

182

183

private void reloadSharedSettings() {

184

String theme = sharedKv.decodeString("theme", "default");

185

boolean darkMode = sharedKv.decodeBool("dark_mode", false);

186

// Update UI with new settings

187

updateUI(theme, darkMode);

188

}

189

190

@Override

191

protected void onDestroy() {

192

super.onDestroy();

193

// Unregister notifications to prevent memory leaks

194

MMKV.unregisterContentChangeNotify();

195

}

196

}

197

```

198

199

### Process Mode Validation

200

201

Validate that MMKV instances are used with correct process modes to prevent data corruption.

202

203

```java { .api }

204

/**

205

* Manually enable the process mode checker.

206

* Automatically enabled in DEBUG build, disabled in RELEASE build.

207

* Throws exceptions when instances are created with mismatched process modes.

208

*/

209

public static void enableProcessModeChecker();

210

211

/**

212

* Manually disable the process mode checker.

213

* When enabled, MMKV throws exceptions for process mode mismatches.

214

*/

215

public static void disableProcessModeChecker();

216

```

217

218

**Usage Example:**

219

220

```java

221

public class ProcessModeValidationExample {

222

223

public void setupProcessModeValidation() {

224

if (BuildConfig.DEBUG) {

225

// Enable strict checking in debug builds

226

MMKV.enableProcessModeChecker();

227

}

228

229

try {

230

// This will work fine

231

MMKV singleKv = MMKV.mmkvWithID("single_data", MMKV.SINGLE_PROCESS_MODE);

232

233

// If another process already opened "single_data" with MULTI_PROCESS_MODE,

234

// this will throw IllegalArgumentException in debug mode

235

MMKV singleKv2 = MMKV.mmkvWithID("single_data", MMKV.SINGLE_PROCESS_MODE);

236

237

} catch (IllegalArgumentException e) {

238

Log.e("MMKV", "Process mode mismatch detected", e);

239

// Handle the error - maybe use MULTI_PROCESS_MODE instead

240

MMKV multiKv = MMKV.mmkvWithID("single_data", MMKV.MULTI_PROCESS_MODE);

241

}

242

}

243

}

244

```

245

246

### Anonymous Shared Memory (Ashmem)

247

248

Use anonymous shared memory for inter-process communication without disk persistence.

249

250

```java { .api }

251

/**

252

* Create an MMKV instance based on Anonymous Shared Memory.

253

* Not synced to any disk files - data is lost when all processes exit.

254

* @param context The Android app context

255

* @param mmapID The unique ID of the MMKV instance

256

* @param size The maximum size of Anonymous Shared Memory (cannot grow dynamically)

257

* @param mode The process mode

258

* @param cryptKey The encryption key

259

* @return The ashmem-based MMKV instance

260

*/

261

public static MMKV mmkvWithAshmemID(Context context, String mmapID, int size,

262

int mode, String cryptKey);

263

264

/**

265

* Get the file descriptor of the ashmem MMKV file.

266

* @return The file descriptor

267

*/

268

public int ashmemFD();

269

270

/**

271

* Get the file descriptor of the ashmem MMKV crc file.

272

* @return The meta file descriptor

273

*/

274

public int ashmemMetaFD();

275

276

/**

277

* Create MMKV instance from ashmem file descriptors.

278

* @param mmapID The unique ID

279

* @param fd The ashmem file descriptor

280

* @param metaFD The ashmem meta file descriptor

281

* @param cryptKey The encryption key

282

* @return The MMKV instance

283

*/

284

public static MMKV mmkvWithAshmemFD(String mmapID, int fd, int metaFD, String cryptKey);

285

```

286

287

**Usage Example:**

288

289

```java

290

public class AshmemExample {

291

292

// In main process - create ashmem instance

293

public MMKV createSharedMemoryStorage(Context context) {

294

try {

295

// Create 1MB ashmem instance for inter-process sharing

296

MMKV ashmemKv = MMKV.mmkvWithAshmemID(

297

context,

298

"shared_memory_data",

299

1024 * 1024, // 1MB maximum size

300

MMKV.MULTI_PROCESS_MODE,

301

null // No encryption for simplicity

302

);

303

304

// Store some data

305

ashmemKv.encode("process_id", android.os.Process.myPid());

306

ashmemKv.encode("timestamp", System.currentTimeMillis());

307

308

// Get file descriptors for sharing with other processes

309

int fd = ashmemKv.ashmemFD();

310

int metaFD = ashmemKv.ashmemMetaFD();

311

312

Log.d("MMKV", String.format("Created ashmem MMKV: fd=%d, metaFD=%d", fd, metaFD));

313

314

return ashmemKv;

315

316

} catch (Exception e) {

317

Log.e("MMKV", "Failed to create ashmem MMKV", e);

318

return null;

319

}

320

}

321

322

// In other process - access via ContentProvider (handled automatically)

323

public MMKV getSharedMemoryStorage(Context context) {

324

try {

325

// This automatically uses MMKVContentProvider to get the ashmem instance

326

MMKV sharedKv = MMKV.mmkvWithAshmemID(

327

context,

328

"shared_memory_data",

329

1024 * 1024,

330

MMKV.MULTI_PROCESS_MODE,

331

null

332

);

333

334

// Read data shared from main process

335

int processId = sharedKv.decodeInt("process_id", -1);

336

long timestamp = sharedKv.decodeLong("timestamp", 0);

337

338

Log.d("MMKV", String.format("Shared data: pid=%d, time=%d", processId, timestamp));

339

340

return sharedKv;

341

342

} catch (Exception e) {

343

Log.e("MMKV", "Failed to access shared ashmem MMKV", e);

344

return null;

345

}

346

}

347

}

348

```

349

350

### ContentProvider Integration

351

352

MMKV automatically provides a ContentProvider for ashmem-based inter-process communication.

353

354

```java { .api }

355

/**

356

* Helper ContentProvider for ashmem-based MMKV instances.

357

* Automatically handles file descriptor sharing between processes.

358

*/

359

public class MMKVContentProvider extends ContentProvider {

360

// Constants for ContentProvider communication

361

protected static final String KEY = "KEY";

362

protected static final String KEY_SIZE = "KEY_SIZE";

363

protected static final String KEY_MODE = "KEY_MODE";

364

protected static final String KEY_CRYPT = "KEY_CRYPT";

365

protected static final String FUNCTION_NAME = "mmkvFromAshmemID";

366

367

/**

368

* Get the content URI for this provider.

369

* @param context The Android app context

370

* @return The content URI or null if invalid authority

371

*/

372

protected static Uri contentUri(Context context);

373

374

/**

375

* Get the process name by process ID.

376

* @param context The Android app context

377

* @param pid The process ID

378

* @return The process name or null if not found

379

*/

380

protected static String getProcessNameByPID(Context context, int pid);

381

382

// ContentProvider lifecycle methods

383

@Override

384

public boolean onCreate();

385

386

/**

387

* Handle ashmem MMKV creation calls.

388

* @param method The method name (should be FUNCTION_NAME)

389

* @param mmapID The MMKV instance ID

390

* @param extras Bundle containing size, mode, and crypto key

391

* @return Bundle containing ParcelableMMKV instance

392

*/

393

@Override

394

public Bundle call(String method, String mmapID, Bundle extras);

395

396

@Override

397

public String getType(Uri uri);

398

399

// Unsupported ContentProvider methods (throw UnsupportedOperationException)

400

@Override

401

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);

402

403

@Override

404

public Uri insert(Uri uri, ContentValues values);

405

406

@Override

407

public int delete(Uri uri, String selection, String[] selectionArgs);

408

409

@Override

410

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);

411

}

412

```

413

414

**AndroidManifest.xml Configuration:**

415

416

```xml

417

<!-- Add to your AndroidManifest.xml for ashmem support -->

418

<provider

419

android:name="com.tencent.mmkv.MMKVContentProvider"

420

android:authorities="${applicationId}.mmkv.provider"

421

android:exported="false" />

422

```

423

424

**Usage Example:**

425

426

```java

427

// The ContentProvider is used automatically when creating ashmem instances

428

// No manual setup required beyond AndroidManifest.xml declaration

429

430

public void demonstrateAutomaticContentProvider(Context context) {

431

// This automatically uses MMKVContentProvider internally

432

MMKV ashmemKv = MMKV.mmkvWithAshmemID(

433

context,

434

"auto_shared_data",

435

512 * 1024, // 512KB

436

MMKV.MULTI_PROCESS_MODE,

437

"shared-key"

438

);

439

440

// The ContentProvider handles the cross-process communication transparently

441

ashmemKv.encode("message", "Hello from " + getProcessName());

442

443

String processName = MMKVContentProvider.getProcessNameByPID(context,

444

android.os.Process.myPid());

445

Log.d("MMKV", "Current process: " + processName);

446

}

447

```

448

449

### Best Practices for Multi-Process Usage

450

451

Guidelines for effective multi-process MMKV usage.

452

453

**Usage Example:**

454

455

```java

456

public class MultiProcessBestPractices {

457

458

/**

459

* Proper multi-process MMKV setup with error handling.

460

*/

461

public static MMKV createSafeMultiProcessMMKV(String instanceId) {

462

try {

463

// Always use MULTI_PROCESS_MODE for shared data

464

MMKV kv = MMKV.mmkvWithID(instanceId, MMKV.MULTI_PROCESS_MODE);

465

466

// Verify it's actually in multi-process mode

467

if (!kv.isMultiProcess()) {

468

Log.w("MMKV", "Expected multi-process mode but got single-process");

469

}

470

471

return kv;

472

473

} catch (RuntimeException e) {

474

Log.e("MMKV", "Failed to create multi-process MMKV: " + instanceId, e);

475

throw e;

476

}

477

}

478

479

/**

480

* Safe atomic operation with proper locking.

481

*/

482

public static void atomicUpdate(MMKV kv, String key, AtomicUpdateFunction updateFunc) {

483

if (!kv.isMultiProcess()) {

484

// No locking needed for single-process

485

updateFunc.update(kv, key);

486

return;

487

}

488

489

kv.lock();

490

try {

491

updateFunc.update(kv, key);

492

} finally {

493

kv.unlock();

494

}

495

}

496

497

/**

498

* Batch operations with single lock for better performance.

499

*/

500

public static void batchUpdate(MMKV kv, BatchOperation operation) {

501

if (kv.isMultiProcess()) {

502

kv.lock();

503

}

504

505

try {

506

operation.execute(kv);

507

} finally {

508

if (kv.isMultiProcess()) {

509

kv.unlock();

510

}

511

}

512

}

513

514

interface AtomicUpdateFunction {

515

void update(MMKV kv, String key);

516

}

517

518

interface BatchOperation {

519

void execute(MMKV kv);

520

}

521

}

522

523

// Usage examples

524

MMKV sharedKv = MultiProcessBestPractices.createSafeMultiProcessMMKV("user_settings");

525

526

// Atomic counter increment

527

MultiProcessBestPractices.atomicUpdate(sharedKv, "counter", (kv, key) -> {

528

int current = kv.decodeInt(key, 0);

529

kv.encode(key, current + 1);

530

});

531

532

// Batch update multiple values

533

MultiProcessBestPractices.batchUpdate(sharedKv, (kv) -> {

534

kv.encode("batch_update_time", System.currentTimeMillis());

535

kv.encode("batch_process_id", android.os.Process.myPid());

536

kv.encode("batch_counter", kv.decodeInt("batch_counter", 0) + 1);

537

});

538

```

539

540

## Types

541

542

```java { .api }

543

public interface MMKVContentChangeNotification {

544

/**

545

* Called when content is changed by another process.

546

* @param mmapID The unique ID of the changed MMKV instance

547

*/

548

void onContentChangedByOuterProcess(String mmapID);

549

}

550

```

551

552

## Constants

553

554

```java { .api }

555

// Process mode constants

556

public static final int SINGLE_PROCESS_MODE = 1 << 0;

557

public static final int MULTI_PROCESS_MODE = 1 << 1;

558

public static final int READ_ONLY_MODE = 1 << 5;

559

```

560

561

## Important Notes

562

563

1. **Process Mode Consistency**: All processes must use the same process mode for a given MMKV instance ID

564

2. **Locking**: Use explicit locking only for atomic operations that span multiple read/write calls

565

3. **Performance**: Multi-process mode has additional overhead compared to single-process mode

566

4. **Ashmem Size**: Anonymous shared memory size cannot be changed after creation - plan appropriately

567

5. **ContentProvider**: Required in AndroidManifest.xml for ashmem functionality

568

6. **Change Notifications**: Require manual triggering via `checkContentChangedByOuterProcess()`

569

7. **Process Mode Checker**: Enable in debug builds to catch configuration errors early