1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include "updatecheck.hxx"
23 #include "updatecheckconfig.hxx"
24 #include "updatehdl.hxx"
25 #include "updateprotocol.hxx"
31 #include <cppuhelper/implbase.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <comphelper/diagnose_ex.hxx>
35 #include <com/sun/star/frame/Desktop.hpp>
36 #include <com/sun/star/frame/XTerminateListener.hpp>
37 #include <com/sun/star/task/XJob.hpp>
39 namespace beans
= com::sun::star::beans
;
40 namespace frame
= com::sun::star::frame
;
41 namespace lang
= com::sun::star::lang
;
42 namespace task
= com::sun::star::task
;
43 namespace uno
= com::sun::star::uno
;
48 class InitUpdateCheckJobThread
: public osl::Thread
51 InitUpdateCheckJobThread( const uno::Reference
< uno::XComponentContext
> &xContext
,
52 const uno::Sequence
< beans::NamedValue
> &xParameters
,
55 virtual void SAL_CALL
run() override
;
57 void setTerminating();
60 osl::Condition m_aCondition
;
61 uno::Reference
<uno::XComponentContext
> m_xContext
;
62 uno::Sequence
<beans::NamedValue
> m_xParameters
;
67 rtl::Reference
<UpdateCheck
> m_controller
;
70 class UpdateCheckJob
:
71 public ::cppu::WeakImplHelper
< task::XJob
, lang::XServiceInfo
, frame::XTerminateListener
>
73 virtual ~UpdateCheckJob() override
;
78 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
79 css::uno::Reference
<css::frame::XDesktop2
> const & desktop
):
80 m_xContext(context
), m_xDesktop(desktop
)
84 virtual uno::Any SAL_CALL
execute(const uno::Sequence
<beans::NamedValue
>&) override
;
87 virtual OUString SAL_CALL
getImplementationName() override
;
88 virtual sal_Bool SAL_CALL
supportsService(OUString
const & serviceName
) override
;
89 virtual uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
92 virtual void SAL_CALL
disposing( css::lang::EventObject
const & evt
) override
;
95 virtual void SAL_CALL
queryTermination( lang::EventObject
const & evt
) override
;
96 virtual void SAL_CALL
notifyTermination( lang::EventObject
const & evt
) override
;
99 uno::Reference
<uno::XComponentContext
> m_xContext
;
102 uno::Reference
< frame::XDesktop2
> m_xDesktop
;
103 std::unique_ptr
< InitUpdateCheckJobThread
> m_pInitThread
;
105 void handleExtensionUpdates( const uno::Sequence
< beans::NamedValue
> &rListProp
);
106 void terminateAndJoinThread();
109 InitUpdateCheckJobThread::InitUpdateCheckJobThread(
110 const uno::Reference
< uno::XComponentContext
> &xContext
,
111 const uno::Sequence
< beans::NamedValue
> &xParameters
,
113 m_xContext( xContext
),
114 m_xParameters( xParameters
),
115 m_bShowDialog( bShowDialog
),
116 m_bTerminating( false )
122 void SAL_CALL
InitUpdateCheckJobThread::run()
124 osl_setThreadName("InitUpdateCheckJobThread");
126 if (!m_bShowDialog
) {
127 TimeValue tv
= { 25, 0 };
128 m_aCondition
.wait( &tv
);
129 if ( m_bTerminating
)
134 rtl::Reference
< UpdateCheck
> aController( UpdateCheck::get() );
135 // At least for the automatic ("onFirstVisibleTask", i.e., !m_bShowDialog) check, wait for
136 // m_controller during setTerminating, to prevent m_controller from still having threads
137 // running during exit (ideally, we would make sure that all threads are joined before exit,
138 // but the UpdateCheck logic is rather convoluted, so play it safe for now and only address
139 // the automatic update check that is known to cause issues during `make check`, not the
140 // manually triggered update check scenario):
141 if (!m_bShowDialog
) {
142 std::scoped_lock
l(m_mutex
);
143 m_controller
= aController
;
145 aController
->initialize( m_xParameters
, m_xContext
);
148 aController
->showDialog( true );
149 } catch (const uno::Exception
&) {
150 // fdo#64962 - don't bring the app down on some unexpected exception.
151 TOOLS_WARN_EXCEPTION("extensions.update", "Caught init update exception, thread terminated" );
153 std::scoped_lock
l(m_mutex
);
154 m_controller
.clear();
159 void InitUpdateCheckJobThread::setTerminating() {
160 m_bTerminating
= true;
162 rtl::Reference
<UpdateCheck
> controller
;
164 std::scoped_lock
l(m_mutex
);
165 std::swap(controller
, m_controller
);
167 if (controller
.is()) {
168 controller
->waitForUpdateCheckFinished();
172 UpdateCheckJob::~UpdateCheckJob()
177 UpdateCheckJob::execute(const uno::Sequence
<beans::NamedValue
>& namedValues
)
179 for ( sal_Int32 n
=namedValues
.getLength(); n
-- > 0; )
181 if ( namedValues
[ n
].Name
== "DynamicData" )
183 uno::Sequence
<beans::NamedValue
> aListProp
;
184 if ( namedValues
[n
].Value
>>= aListProp
)
186 for ( sal_Int32 i
=aListProp
.getLength(); i
-- > 0; )
188 if ( aListProp
[ i
].Name
== "updateList" )
190 handleExtensionUpdates( aListProp
);
198 uno::Sequence
<beans::NamedValue
> aConfig
=
199 getValue
< uno::Sequence
<beans::NamedValue
> > (namedValues
, "JobConfig");
201 /* Determine the way we got invoked here -
202 * see Developers Guide Chapter "4.7.2 Jobs" to understand the magic
205 uno::Sequence
<beans::NamedValue
> aEnvironment
=
206 getValue
< uno::Sequence
<beans::NamedValue
> > (namedValues
, "Environment");
208 OUString aEventName
= getValue
< OUString
> (aEnvironment
, "EventName");
210 auto thread
= std::make_unique
<InitUpdateCheckJobThread
>(
212 aEventName
!= "onFirstVisibleTask");
214 std::scoped_lock
l(m_mutex
);
215 m_pInitThread
= std::move(thread
);
222 void UpdateCheckJob::handleExtensionUpdates( const uno::Sequence
< beans::NamedValue
> &rListProp
)
225 uno::Sequence
< uno::Sequence
< OUString
> > aList
=
226 getValue
< uno::Sequence
< uno::Sequence
< OUString
> > > ( rListProp
, "updateList" );
227 bool bPrepareOnly
= getValue
< bool > ( rListProp
, "prepareOnly" );
229 // we will first store any new found updates and then check, if there are any
231 storeExtensionUpdateInfos( m_xContext
, aList
);
236 bool bHasUpdates
= checkForPendingUpdates( m_xContext
);
238 rtl::Reference
<UpdateCheck
> aController( UpdateCheck::get() );
239 if ( ! aController
.is() )
242 aController
->setHasExtensionUpdates( bHasUpdates
);
244 if ( ! aController
->hasOfficeUpdate() )
247 aController
->setUIState( UPDATESTATE_EXT_UPD_AVAIL
, true );
249 aController
->setUIState( UPDATESTATE_NO_UPDATE_AVAIL
, true );
252 catch( const uno::Exception
& )
254 TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated");
260 UpdateCheckJob::getImplementationName()
262 return "vnd.sun.UpdateCheck";
266 uno::Sequence
< OUString
> SAL_CALL
267 UpdateCheckJob::getSupportedServiceNames()
269 return { "com.sun.star.setup.UpdateCheck" };
273 UpdateCheckJob::supportsService( OUString
const & serviceName
)
275 return cppu::supportsService(this, serviceName
);
280 void SAL_CALL
UpdateCheckJob::disposing( lang::EventObject
const & rEvt
)
282 css::uno::Reference
<css::frame::XDesktop2
> desktop
;
284 std::scoped_lock
l(m_mutex
);
285 if ( rEvt
.Source
== m_xDesktop
) {
286 std::swap(m_xDesktop
, desktop
);
292 terminateAndJoinThread();
293 desktop
->removeTerminateListener( this );
298 // XTerminateListener
299 void SAL_CALL
UpdateCheckJob::queryTermination( lang::EventObject
const & )
303 void UpdateCheckJob::terminateAndJoinThread()
305 std::unique_ptr
<InitUpdateCheckJobThread
> thread
;
307 std::scoped_lock
l(m_mutex
);
308 std::swap(m_pInitThread
, thread
);
310 if (thread
!= nullptr)
312 thread
->setTerminating();
317 void SAL_CALL
UpdateCheckJob::notifyTermination( lang::EventObject
const & )
319 terminateAndJoinThread();
322 } // anonymous namespace
324 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
325 extensions_update_UpdateCheckJob_get_implementation(
326 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
328 css::uno::Reference
<css::frame::XDesktop2
> desktop(
329 css::frame::Desktop::create(context
));
330 rtl::Reference
<UpdateCheckJob
> job(new UpdateCheckJob(context
, desktop
));
331 desktop
->addTerminateListener(job
);
332 return cppu::acquire(job
.get());
336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */