Fix inconsistency between cache and database
[platform/core/appfw/pkgmgr-info.git] / src / common / db_change_observer.cc
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "db_change_observer.hh"
18
19 #include <tzplatform_config.h>
20
21 #include <utility>
22
23 #include "utils/logging.hh"
24
25 #include "pkgmgrinfo_debug.h"
26 #include "pkgmgr-info.h"
27
28 #undef LOG_TAG
29 #define LOG_TAG "PKGMGR_INFO"
30
31 namespace {
32
33 uid_t globaluser_uid = -1;
34
35 uid_t GetGlobalUID() {
36   if (globaluser_uid == (uid_t)-1)
37     globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
38
39   return globaluser_uid;
40 }
41
42 }  // namespace
43
44 namespace pkgmgr_common {
45
46 DbChangeObserver& DbChangeObserver::GetInst() {
47   static DbChangeObserver inst;
48
49   return inst;
50 }
51
52 gboolean DbChangeObserver::OnReceiveEvent(GIOChannel* channel, GIOCondition cond,
53     gpointer user_data) {
54   LOG(WARNING) << "db changed event occured";
55   char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
56   auto db_change = reinterpret_cast<DbChangeObserver*>(user_data);
57   int fd = g_io_channel_unix_get_fd(channel);
58
59   while(read(fd, buf, sizeof(buf)) > 0);
60
61   std::unique_lock<std::shared_mutex> u(db_change->lock_);
62   if (!db_change->changed_) {
63     db_change->changed_ = true;
64     if (db_change->listener_)
65       db_change->listener_->OnDbChanged();
66   }
67
68   return G_SOURCE_CONTINUE;
69 }
70
71 DbChangeObserver::DbChangeObserver() {
72   std::unique_lock<std::shared_mutex> u(lock_);
73   SetGlobalParserDbPath();
74 }
75
76 DbChangeObserver::~DbChangeObserver() {
77   std::unique_lock<std::shared_mutex> u(lock_);
78   Dispose();
79 }
80
81 bool DbChangeObserver::Listen() {
82   std::unique_lock<std::shared_mutex> u(lock_);
83
84   if (!disposed_)
85     return true;
86
87   if (global_parser_db_path_.empty()) {
88     if (!SetGlobalParserDbPath()) {
89       LOG(ERROR) << "Fail to Set GlobalParserDbPath";
90       return false;
91     }
92   }
93
94   disposed_ = false;
95
96   fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
97   if (fd_ == -1) {
98     LOG(ERROR) << "Failed to inotify_init. errno: " << errno;
99     Dispose();
100     return false;
101   }
102
103   wd_ = inotify_add_watch(fd_, global_parser_db_path_.c_str(), IN_MODIFY);
104   if (wd_ == -1) {
105     LOG(ERROR) << "Failed to inotify_add_watch. errno: " << errno;
106     Dispose();
107     return false;
108   }
109
110   channel_ = g_io_channel_unix_new(fd_);
111   if (channel_ == nullptr) {
112     LOG(ERROR) << "Failed to create GIO channel";
113     Dispose();
114     return false;
115   }
116
117   tag_ = g_io_add_watch(channel_, (GIOCondition)(G_IO_IN), OnReceiveEvent, this);
118   if (tag_ == 0) {
119     LOG(ERROR) << "Failed to add watch";
120     Dispose();
121     return false;
122   }
123
124   changed_ = false;
125   disposed_ = false;
126
127   return true;
128 }
129
130 void DbChangeObserver::StopListening() {
131   std::unique_lock<std::shared_mutex> u(lock_);
132
133   Dispose();
134 }
135
136 bool DbChangeObserver::IsChanged() {
137   std::shared_lock<std::shared_mutex> s(lock_);
138   return changed_;
139 }
140
141 void DbChangeObserver::SetChanged(bool changed) {
142   std::unique_lock<std::shared_mutex>s (lock_);
143   changed_ = changed;
144 }
145
146 void DbChangeObserver::Dispose() {
147   if (disposed_)
148     return;
149
150   if (tag_) {
151     g_source_remove(tag_);
152     tag_ = 0;
153   }
154
155   if (channel_ != nullptr) {
156     g_io_channel_unref(channel_);
157     channel_ = nullptr;
158   }
159
160   if (wd_ > 0) {
161     inotify_rm_watch(fd_, wd_);
162     wd_ = 0;
163   }
164
165   if (fd_ > 0) {
166     close(fd_);
167     fd_ = 0;
168   }
169
170   disposed_ = true;
171 }
172
173 bool DbChangeObserver::GetDisposed() {
174   std::shared_lock<std::shared_mutex> s(lock_);
175
176   return disposed_;
177 }
178
179 bool DbChangeObserver::SetGlobalParserDbPath() {
180   char* tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
181   if (tmp_path == nullptr) {
182     LOG(ERROR) << "Fail to global parser db";
183     return false;
184   }
185   global_parser_db_path_ = tmp_path;
186   free(tmp_path);
187   return true;
188 }
189
190 void DbChangeObserver::RegisterEvent(IEvent* listener) {
191   std::unique_lock<std::shared_mutex> s(lock_);
192   listener_ = listener;
193 }
194
195 void DbChangeObserver::UnRegisterEvent() {
196   std::unique_lock<std::shared_mutex> s(lock_);
197   listener_ = nullptr;
198 }
199
200 }  // namespace pkgmgr_common