File: tab_state_storage_service.cc

package info (click to toggle)
chromium 140.0.7339.185-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,193,740 kB
  • sloc: cpp: 35,093,945; ansic: 7,161,670; javascript: 4,199,694; python: 1,441,797; asm: 949,904; xml: 747,515; pascal: 187,748; perl: 88,691; sh: 88,248; objc: 79,953; sql: 52,714; cs: 44,599; fortran: 24,137; makefile: 22,114; tcl: 15,277; php: 13,980; yacc: 9,000; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (142 lines) | stat: -rw-r--r-- 5,640 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab/tab_state_storage_service.h"

#include "base/android/callback_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_bytebuffer.h"
#include "base/android/jni_string.h"
#include "base/android/token_android.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/token.h"
#include "chrome/browser/tab/jni_headers/TabStateStorageService_jni.h"

namespace tabs {

namespace {

void RunJavaCallbackLoadAllTabs(
    JNIEnv* env,
    const base::android::JavaRef<jobject>& j_callback,
    std::vector<tabs_pb::TabState> tab_states) {
  std::vector<base::android::ScopedJavaLocalRef<jobject>> j_tab_state_vector;
  for (tabs_pb::TabState& tab_state : tab_states) {
    base::android::ScopedJavaLocalRef<jobject> j_web_contents_state_buffer;
    if (tab_state.has_web_contents_state_bytes()) {
      // TODO(https://crbug.com/427255040): This is probably leaking memory and
      // should be fixed. No path back from Java when the owning object is
      // destroyed/cleaned/gc'd, and Java currently has no way to tell the
      // backing implementation of the owning object.
      raw_ptr<std::string> web_contents_state_bytes_ptr =
          tab_state.release_web_contents_state_bytes();
      j_web_contents_state_buffer =
          base::android::ScopedJavaLocalRef<jobject>::Adopt(
              env, env->NewDirectByteBuffer(
                       static_cast<void*>(web_contents_state_bytes_ptr->data()),
                       web_contents_state_bytes_ptr->size()));
    }

    base::Token tab_group_token(tab_state.tab_group_id_high(),
                                tab_state.tab_group_id_low());
    base::android::ScopedJavaLocalRef<jobject> j_tab_group_id =
        base::android::TokenAndroid::Create(env, tab_group_token);

    base::android::ScopedJavaLocalRef<jobject> j_tab_state =
        Java_TabStateStorageService_createTabState(
            env, tab_state.parent_id(), tab_state.root_id(),
            tab_state.timestamp_millis(), j_web_contents_state_buffer,
            tab_state.opener_app_id(), tab_state.theme_color(),
            tab_state.launch_type_at_creation(), tab_state.user_agent(),
            tab_state.last_navigation_committed_timestamp_millis(),
            j_tab_group_id, tab_state.tab_has_sensitive_content(),
            tab_state.is_pinned());
    j_tab_state_vector.push_back(j_tab_state);
  }

  base::android::ScopedJavaLocalRef<jclass> type =
      base::android::GetClass(env, "org/chromium/chrome/browser/tab/TabState");
  base::android::ScopedJavaLocalRef<jobjectArray> j_tab_state_array =
      base::android::ToTypedJavaArrayOfObjects(env, j_tab_state_vector,
                                               type.obj());
  base::android::RunObjectCallbackAndroid(j_callback, j_tab_state_array);
}

}  // namespace

TabStateStorageService::TabStateStorageService(
    std::unique_ptr<TabStateStorageBackend> tab_backend)
    : tab_backend_(std::move(tab_backend)) {
  java_ref_.Reset(Java_TabStateStorageService_create(
      base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this)));
  tab_backend_->Initialize();
}

TabStateStorageService::~TabStateStorageService() = default;

base::android::ScopedJavaLocalRef<jobject>
TabStateStorageService::GetJavaObject() {
  return base::android::ScopedJavaLocalRef<jobject>(java_ref_);
}

void TabStateStorageService::SaveTab(
    JNIEnv* env,
    int id,
    int parent_collection_id,
    std::string position,
    int parent_tab_id,
    int root_id,
    long timestamp_millis,
    const jni_zero::JavaParamRef<jobject>& web_contents_state_buffer,
    std::string opener_app_id,
    int theme_color,
    int launch_type_at_creation,
    int user_agent,
    long last_navigation_committed_timestamp_millis,
    const jni_zero::JavaParamRef<jobject>& j_tab_group_id,
    bool tab_has_sensitive_content,
    bool is_pinned) {
  tabs_pb::TabState tab_state;
  tab_state.set_parent_id(parent_tab_id);
  tab_state.set_root_id(root_id);
  tab_state.set_timestamp_millis(timestamp_millis);

  if (web_contents_state_buffer) {
    base::span<const uint8_t> span =
        base::android::JavaByteBufferToSpan(env, web_contents_state_buffer);
    std::string state_as_string(span.begin(), span.end());
    tab_state.set_web_contents_state_bytes(state_as_string);
  }

  tab_state.set_opener_app_id(opener_app_id);
  tab_state.set_theme_color(theme_color);
  tab_state.set_launch_type_at_creation(launch_type_at_creation);
  tab_state.set_user_agent(user_agent);
  tab_state.set_last_navigation_committed_timestamp_millis(
      last_navigation_committed_timestamp_millis);

  if (j_tab_group_id) {
    base::Token tab_group_id =
        base::android::TokenAndroid::FromJavaToken(env, j_tab_group_id);
    tab_state.set_tab_group_id_high(tab_group_id.high());
    tab_state.set_tab_group_id_low(tab_group_id.low());
  }

  tab_state.set_tab_has_sensitive_content(tab_has_sensitive_content);
  tab_state.set_is_pinned(is_pinned);
  tab_backend_->SaveTabState(id, parent_collection_id, position, tab_state);
}

void TabStateStorageService::LoadAllTabs(
    JNIEnv* env,
    const jni_zero::JavaParamRef<jobject>& j_callback) {
  // TODO(skym): Change to also pass back id, parent_collection_id, position.
  tab_backend_->LoadAllTabStates(
      base::BindOnce(&RunJavaCallbackLoadAllTabs, env,
                     jni_zero::ScopedJavaGlobalRef<jobject>(j_callback)));
}

}  // namespace tabs